ircu2.10.12 pk910 fork
[ircu2.10.12-pk.git] / patches / diffs / login-on-connect.diff
1 Index: ChangeLog
2 ===================================================================
3 RCS file: /home/coder-com/cvs/ircu2.10/ChangeLog,v
4 retrieving revision 1.340
5 diff -u -r1.340 ChangeLog
6 --- ChangeLog   2002/04/12 00:19:52     1.340
7 +++ ChangeLog   2002/04/12 13:17:10
8 @@ -1,5 +1,33 @@
9  2002-04-12  Alex Badea  <vampire@p16.pub.ro>
10  
11 +       * include/ircd_features.h: new feature LOGIN_ON_CONNECT
12 +
13 +       * ircd/ircd_features.c: new feature LOGIN_ON_CONNECT
14 +
15 +       * include/client.h (struct Client): new fields for storing
16 +       bot name, username and password for login-on-connect
17 +
18 +       * ircd/m_account.c: extensions for login-on-connect: route
19 +       and process auth-request and auth-reply messages
20 +
21 +       * ircd/m_pass.c: store bot name, username and password for
22 +       service login
23 +
24 +       * ircd/m_user.c: store username/hostname for the client
25 +       even if he finished registration, as register_user may not
26 +       do that anymore
27 +
28 +       * ircd/s_user.c (register_user): if the client specified
29 +       a service login in the PASS command, attempt to log him in;
30 +       also, don't set his hostname if it was set remotely by a
31 +       service bot
32 +
33 +       * doc/example.conf: default value for FEAT_LOGIN_ON_CONNECT
34 +
35 +       * doc/readme.features: documented FEAT_LOGIN_ON_CONNECT
36 +
37 +2002-04-12  Alex Badea  <vampire@p16.pub.ro>
38 +
39         * ircd/m_invite.c: don't propagate invites for local channels
40  
41         * include/patchlevel.h (PATCHLEVEL): bump patchlevel
42 Index: doc/example.conf
43 ===================================================================
44 RCS file: /home/coder-com/cvs/ircu2.10/doc/example.conf,v
45 retrieving revision 1.20
46 diff -u -r1.20 example.conf
47 --- doc/example.conf    2002/04/03 15:23:47     1.20
48 +++ doc/example.conf    2002/04/12 13:17:10
49 @@ -702,6 +702,7 @@
50  #  "HOST_HIDING"="FALSE";
51  #  "HIDDEN_HOST"="users.undernet.org";
52  #  "HIDDEN_IP"="127.0.0.1";
53 +#  "LOGIN_ON_CONNECT"="FALSE";
54  #  "KILLCHASETIMELIMIT"="30";
55  #  "MAXCHANNELSPERUSER"="10";
56  #  "AVBANLEN"="40";
57 Index: doc/readme.features
58 ===================================================================
59 RCS file: /home/coder-com/cvs/ircu2.10/doc/readme.features,v
60 retrieving revision 1.5
61 diff -u -r1.5 readme.features
62 --- doc/readme.features 2002/04/03 15:23:47     1.5
63 +++ doc/readme.features 2002/04/12 13:17:10
64 @@ -242,6 +242,13 @@
65  This selects a fake IP to be shown on /USERIP and /WHO %i when the
66  target has a hidden host (see HOST_HIDING).
67  
68 +LOGIN_ON_CONNECT
69 +  * Type: boolean
70 +  * Default: FALSE
71 +
72 +This selects whether local clients can use specify a service bot login
73 +in the connection phase. Read readme.login-on-connect for more details.
74 +
75  KILLCHASETIMELIMIT
76   * Type: integer
77   * Default: 30
78 Index: include/client.h
79 ===================================================================
80 RCS file: /home/coder-com/cvs/ircu2.10/include/client.h,v
81 retrieving revision 1.26
82 diff -u -r1.26 client.h
83 --- include/client.h    2002/04/05 11:36:58     1.26
84 +++ include/client.h    2002/04/12 13:17:10
85 @@ -196,6 +196,10 @@
86    char cli_name[HOSTLEN + 1];   /* Unique name of the client, nick or host */
87    char cli_username[USERLEN + 1]; /* username here now for auth stuff */
88    char cli_info[REALLEN + 1];   /* Free form additional client information */
89 +  
90 +  char *cli_cs_user;           /* channel service authentication (user)... */
91 +  char *cli_cs_pass;           /* ...and password... */
92 +  char *cli_cs_service;                /* ...and the service bot's nick */
93  };
94  
95  #define CLIENT_MAGIC 0x4ca08286
96 Index: include/ircd_features.h
97 ===================================================================
98 RCS file: /home/coder-com/cvs/ircu2.10/include/ircd_features.h,v
99 retrieving revision 1.15
100 diff -u -r1.15 ircd_features.h
101 --- include/ircd_features.h     2002/04/03 15:23:47     1.15
102 +++ include/ircd_features.h     2002/04/12 13:17:10
103 @@ -45,6 +45,7 @@
104    FEAT_HOST_HIDING,
105    FEAT_HIDDEN_HOST,
106    FEAT_HIDDEN_IP,
107 +  FEAT_LOGIN_ON_CONNECT,
108  
109    /* features that probably should not be touched */
110    FEAT_KILLCHASETIMELIMIT,
111 Index: ircd/ircd_features.c
112 ===================================================================
113 RCS file: /home/coder-com/cvs/ircu2.10/ircd/ircd_features.c,v
114 retrieving revision 1.19
115 diff -u -r1.19 ircd_features.c
116 --- ircd/ircd_features.c        2002/04/03 15:23:48     1.19
117 +++ ircd/ircd_features.c        2002/04/12 13:17:10
118 @@ -252,6 +252,7 @@
119    F_B(HOST_HIDING, 0, 0, 0),
120    F_S(HIDDEN_HOST, FEAT_CASE, "users.undernet.org", 0),
121    F_S(HIDDEN_IP, 0, "127.0.0.1", 0),
122 +  F_B(LOGIN_ON_CONNECT, 0, 0, 0),
123  
124    /* features that probably should not be touched */
125    F_I(KILLCHASETIMELIMIT, 0, 30, 0),
126 Index: ircd/m_account.c
127 ===================================================================
128 RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_account.c,v
129 retrieving revision 1.2
130 diff -u -r1.2 m_account.c
131 --- ircd/m_account.c    2002/02/14 00:20:42     1.2
132 +++ ircd/m_account.c    2002/04/12 13:17:10
133 @@ -84,9 +84,11 @@
134  #include "ircd.h"
135  #include "ircd_reply.h"
136  #include "ircd_string.h"
137 +#include "ircd_alloc.h"
138  #include "msg.h"
139  #include "numnicks.h"
140  #include "s_user.h"
141 +#include "s_debug.h"
142  #include "send.h"
143  
144  #include <assert.h>
145 @@ -96,35 +98,108 @@
146   *
147   * parv[0] = sender prefix
148   * parv[1] = numeric of client to act on
149 - * parv[2] = account name (12 characters or less)
150 + * parv[2] = message type
151 + *
152 + * for *parv[2] == 'R' (remote auth):
153 + * parv[3] = account name (12 characters or less)
154 + *
155 + * for *parv[2] == 'C' (auth check):
156 + * parv[3] = numeric of client to check
157 + * parv[4] = username
158 + * parv[parc-1] = password
159 + *
160 + * for *parv[2] == 'A' (auth ok) or
161 + * for *parv[2] == 'D' (auth denied) or
162 + * parv[3] = numeric of client to check 
163   */
164  int ms_account(struct Client* cptr, struct Client* sptr, int parc,
165                char* parv[])
166  {
167    struct Client *acptr;
168 +  char type;
169  
170    if (parc < 3)
171      return need_more_params(sptr, "ACCOUNT");
172 +  
173 +  if (parc < 4) {
174 +    /* old-style message, remap it */
175 +    parv[4] = NULL;
176 +    parv[3] = parv[2];
177 +    parv[2] = "R";
178 +  }
179  
180    if (!IsServer(sptr))
181      return protocol_violation(cptr, "ACCOUNT from non-server %s",
182                               cli_name(sptr));
183 -
184 -  if (!(acptr = findNUser(parv[1])))
185 -    return 0; /* Ignore ACCOUNT for a user that QUIT; probably crossed */
186 -
187 -  if (IsAccount(acptr))
188 -    return protocol_violation(cptr, "ACCOUNT for already registered user %s "
189 -                             "(%s -> %s)", cli_name(acptr),
190 -                             cli_user(acptr)->account, parv[2]);
191 -
192 -  assert(0 == cli_user(acptr)->account[0]);
193 -
194 -  ircd_strncpy(cli_user(acptr)->account, parv[2], ACCOUNTLEN);
195 -  hide_hostmask(acptr, FLAGS_ACCOUNT);
196  
197 -  sendcmdto_serv_butone(sptr, CMD_ACCOUNT, cptr, "%C %s", acptr,
198 -                       cli_user(acptr)->account);
199 +  type = *parv[2];
200 +  if (type == 'R') {
201 +    if (!(acptr = findNUser(parv[1])))
202 +      return 0; /* Ignore ACCOUNT for a user that QUIT; probably crossed */
203 +
204 +    if (IsAccount(acptr))
205 +      return protocol_violation(cptr, "ACCOUNT for already registered user %s "
206 +                               "(%s -> %s)", cli_name(acptr),
207 +                               cli_user(acptr)->account, parv[3]);
208 +
209 +    assert(0 == cli_user(acptr)->account[0]);
210 +
211 +    ircd_strncpy(cli_user(acptr)->account, parv[3], ACCOUNTLEN);
212 +    hide_hostmask(acptr, FLAGS_ACCOUNT);
213 +
214 +#if 0
215 +    /* XXX Enable this when all servers speak the same language */
216 +    sendcmdto_serv_butone(sptr, CMD_ACCOUNT, cptr, "%C R %s", acptr,
217 +                         cli_user(acptr)->account);
218 +#else
219 +    sendcmdto_serv_butone(sptr, CMD_ACCOUNT, cptr, "%C %s", acptr,
220 +                         cli_user(acptr)->account);
221 +#endif
222 +  } else {
223 +    if (!(acptr = findNUser(parv[1])) && !(acptr = FindNServer(parv[1])))
224 +      return 0;
225 +
226 +    if (type == 'C' && parc < 6)
227 +      return need_more_params(sptr, "ACCOUNT");
228 +
229 +    if (!IsMe(acptr)) {
230 +      /* in-transit message, forward it */
231 +      sendcmdto_one(sptr, CMD_ACCOUNT, acptr,
232 +                   type == 'C' ? "%C %s %s %s :%s" : "%C %s %s",
233 +                   acptr, parv[2], parv[3], parv[4], parv[parc-1]);
234 +      return 0;
235 +    }
236 +    
237 +    /* the message is for me, process it */
238 +    if (type == 'C')
239 +      return protocol_violation(cptr, "ACCOUNT check (%s %s %s)", parv[3], parv[4], parv[parc-1]);
240 +
241 +    if (!(acptr = findNUser(parv[3])))
242 +      return 0;
243 +    if (IsRegistered(acptr) || !acptr->cli_cs_service)
244 +      return protocol_violation(cptr, "Invalid ACCOUNT %s for %s", parv[2], cli_name(acptr));
245 +    
246 +    if (type == 'A') {
247 +      ircd_strncpy(cli_user(acptr)->account, acptr->cli_cs_user, ACCOUNTLEN);
248 +      hide_hostmask(acptr, FLAGS_ACCOUNT | FLAGS_HIDDENHOST);
249 +    }
250 +    
251 +    sendcmdto_one(&me, CMD_NOTICE, acptr, "%C :AUTHENTICATION %s as %s", acptr,
252 +                 type == 'A' ? "SUCCESSFUL" : "FAILED",
253 +                 acptr->cli_cs_user);
254 +
255 +    MyFree(acptr->cli_cs_service);
256 +    MyFree(acptr->cli_cs_user);
257 +    MyFree(acptr->cli_cs_pass);
258 +    acptr->cli_cs_service = acptr->cli_cs_user = acptr->cli_cs_pass = NULL;
259 +
260 +    if (type != 'A') {
261 +      sendcmdto_one(&me, CMD_NOTICE, acptr, "%C :Type /QUOTE PASS to connect anyway", acptr);
262 +      return 0;
263 +    }
264 +    
265 +    return register_user(acptr, acptr, cli_name(acptr), cli_user(acptr)->username);
266 +  }
267  
268    return 0;
269  }
270 Index: ircd/m_pass.c
271 ===================================================================
272 RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_pass.c,v
273 retrieving revision 1.7
274 diff -u -r1.7 m_pass.c
275 --- ircd/m_pass.c       2001/06/29 15:51:02     1.7
276 +++ ircd/m_pass.c       2002/04/12 13:17:10
277 @@ -84,7 +84,11 @@
278  #include "client.h"
279  #include "ircd_reply.h"
280  #include "ircd_string.h"
281 +#include "ircd_alloc.h"
282 +#include "ircd_features.h"
283 +#include "s_user.h"
284  #include "send.h"
285 +#include "struct.h"
286  
287  #include <assert.h>
288  
289 @@ -99,15 +103,28 @@
290    assert(cptr == sptr);
291    assert(!IsRegistered(sptr));
292  
293 -  if (EmptyString(password))
294 -    return need_more_params(cptr, "PASS");
295 -
296    /* TODO: For protocol negotiation */
297  #if 0
298    if (ircd_strcmp(password,"PROT")==0) {
299         /* Do something here */
300    }
301  #endif
302 -  ircd_strncpy(cli_passwd(cptr), password, PASSWDLEN);
303 +
304 +  if (!EmptyString(password))
305 +    ircd_strncpy(cli_passwd(cptr), password, PASSWDLEN);
306 +
307 +  if (!feature_bool(FEAT_LOGIN_ON_CONNECT) || cptr->cli_cs_service)
308 +    return 0;
309 +
310 +  if (parc > 3) {
311 +    DupString(cptr->cli_cs_service, parv[parc-3]);
312 +    DupString(cptr->cli_cs_user, parv[parc-2]);
313 +    DupString(cptr->cli_cs_pass, parv[parc-1]);
314 +  }
315 +
316 +  /* Deal with password retries */
317 +  if ((cli_name(cptr))[0] && cli_cookie(cptr) == COOKIE_VERIFIED)
318 +    return register_user(cptr, cptr, cli_name(cptr), cli_user(cptr)->username);
319 +
320    return 0;
321  }
322 Index: ircd/m_user.c
323 ===================================================================
324 RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_user.c,v
325 retrieving revision 1.7
326 diff -u -r1.7 m_user.c
327 --- ircd/m_user.c       2001/06/08 23:12:17     1.7
328 +++ ircd/m_user.c       2002/04/12 13:17:10
329 @@ -142,16 +142,14 @@
330  
331    user->server = &me;
332    ircd_strncpy(cli_info(cptr), info, REALLEN);
333 +  ircd_strncpy(user->username, username, USERLEN);
334 +  ircd_strncpy(user->host, cli_sockhost(cptr), HOSTLEN);
335  
336    if ((cli_name(cptr))[0] && cli_cookie(cptr) == COOKIE_VERIFIED) {
337      /*
338       * NICK and PONG already received, now we have USER...
339       */
340      return register_user(cptr, sptr, cli_name(sptr), username);
341 -  }
342 -  else {
343 -    ircd_strncpy(user->username, username, USERLEN);
344 -    ircd_strncpy(user->host, cli_sockhost(cptr), HOSTLEN);
345    }
346    return 0;
347  }
348 Index: ircd/s_user.c
349 ===================================================================
350 RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_user.c,v
351 retrieving revision 1.58
352 diff -u -r1.58 s_user.c
353 --- ircd/s_user.c       2002/04/05 11:36:59     1.58
354 +++ ircd/s_user.c       2002/04/12 13:17:10
355 @@ -394,6 +394,25 @@
356    parv[0] = cli_name(sptr);
357    parv[1] = parv[2] = NULL;
358  
359 +  if (MyConnect(sptr) && sptr->cli_cs_service && sptr->cli_cs_user && sptr->cli_cs_pass) {
360 +    struct Client *acptr;
361 +    
362 +    if (!(acptr = FindUser(sptr->cli_cs_service)) || !IsChannelService(acptr)) {
363 +      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Service '%s' is not available", sptr, sptr->cli_cs_service);
364 +      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Type /QUOTE PASS to connect anyway", sptr);
365 +      MyFree(sptr->cli_cs_service);
366 +      MyFree(sptr->cli_cs_user);
367 +      MyFree(sptr->cli_cs_pass);
368 +      sptr->cli_cs_service = sptr->cli_cs_user = sptr->cli_cs_pass = NULL;
369 +    } else {
370 +      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Attempting service login to %s",
371 +                   sptr, cli_name(acptr));
372 +      sendcmdto_one(&me, CMD_ACCOUNT, acptr, "%C C %s%s %s :%s", acptr,
373 +                   NumNick(sptr), sptr->cli_cs_user, sptr->cli_cs_pass);
374 +    }
375 +    return 0;
376 +  }
377 +
378    if (MyConnect(sptr))
379    {
380      static time_t last_too_many1;
381 @@ -441,7 +460,9 @@
382          IPcheck_connect_fail(cli_ip(sptr));
383          return exit_client(cptr, sptr, &me, "Unknown error -- Try again");
384      }
385 -    ircd_strncpy(user->host, cli_sockhost(sptr), HOSTLEN);
386 +    /* The host might be already set from login-on-connect */
387 +    if (!HasHiddenHost(sptr))
388 +           ircd_strncpy(user->host, cli_sockhost(sptr), HOSTLEN);
389      ircd_strncpy(user->realhost, cli_sockhost(sptr), HOSTLEN);
390      aconf = cli_confs(sptr)->value.aconf;
391  
392 --- /dev/null   Thu Aug 24 12:00:32 2000
393 +++ doc/readme.login-on-connect Fri Apr 12 16:16:56 2002
394 @@ -0,0 +1,182 @@
395 +1. This feature is experimental.
396 +
397 +2. The main point is to allow clients to log in to a service bot (i.e., X)
398 +*before* being announced to the network. Otherwise, a combination of a
399 +malicious user, /ISON, /USERIP and low latency can reveal it's real host/IP
400 +before he gets a chance to log in and set himself +x
401 +
402 +3. Client<->Server changes:
403 +~~~~~~~~~~~~~~~~~~~~~~~~~~~
404 +The PASS command now has the following syntax:
405 +
406 +PASS [optional Client block password] <bot nick> <username> :<passphrase>
407 +
408 +If the client specifies sends such a password message, after sending NICK,
409 +USER and PONG, it's username/passphrase are sent to the specified bot
410 +for validation, while holding the client in the 'registration' state.
411 +If the authentication succeeds, the client's account and umode +x are set,
412 +after which he is introduced to the network, continuing the regular connect
413 +phase. If authentication fails (or the bot is not on the network), the user
414 +is given a chance to retry (he can do this by sending another PASS command),
415 +or to disconnect from the server. If he wishes to connect without a hidden
416 +hostmask, he can send a PASS command with no parameters.
417 +
418 +4. Server<->Server changes:
419 +~~~~~~~~~~~~~~~~~~~~~~~~~~~
420 +The ACCOUNT message now has the following syntax:
421 +
422 +Auth check: 
423 +<client's server numeric> AC <bot's numeric> C <client's numeric> <username> :<passphrase>
424 +Servers send this message to request a service bot to authenticate the client.
425 +Note that <client's numeric> will only be used by the originating server for
426 +matching auth replies, as the user has not yet been announced to the network.
427 +Hubs will have to propagate this message as-is towards the service bot,
428 +much like they do for PRIVMSGs.
429 +
430 +Auth reply:
431 +<bot's server numeric> AC <client's server numeric> A|D <client's numeric>
432 +Service bots send this in reply to an 'auth check' message from a server.
433 +"A" stands for "accepted", "D" for "denied". Again, hubs will have
434 +to proagate this message back to the client's server.
435 +
436 +Remote auth:
437 +<bot's server numeric> AC <client numeric> R <account>
438 +This is the current message used by service bots to announce the network
439 +that a user has logged in. The old format is still supported:
440 +<bot's server numeric> AC <client numeric> <account>
441 +
442 +5. ircu code changes
443 +~~~~~~~~~~~~~~~~~~~~
444 +A new feature, FEAT_LOGIN_ON_CONNECT (default FALSE) will specify whether
445 +ircu will honour the login scheme as specified above for the PASS command.
446 +ircu will route ACCOUNT messages anyway, regardless of this feature's value.
447 +
448 +6. GNUWorld patches
449 +~~~~~~~~~~~~~~~~~~~
450 +A patch follows that will implement auth checks and replies.
451 +
452 +Index: mod.cservice/cservice.cc
453 +===================================================================
454 +RCS file: /cvsroot/gnuworld/gnuworld/mod.cservice/cservice.cc,v
455 +retrieving revision 1.213
456 +diff -u -r1.213 cservice.cc
457 +--- mod.cservice/cservice.cc   10 Apr 2002 19:00:10 -0000      1.213
458 ++++ mod.cservice/cservice.cc   12 Apr 2002 12:33:45 -0000
459 +@@ -2491,15 +2491,45 @@
460 +       {
461 +       case EVT_ACCOUNT:
462 +               {
463 +-              iClient* tmpUser = static_cast< iClient* >( data1 ) ;
464 +-              networkData* tmpData = static_cast< networkData* >(tmpUser->getCustomData(this) ) ;
465 +-              /* Lookup this user account, if its not there.. trouble */
466 +-              sqlUser* theUser = getUserRecord(tmpUser->getAccount());
467 +-              if (theUser)
468 +-                      {
469 +-                      tmpData->currentUser = theUser;
470 +-                      theUser->addAuthedClient(tmpUser);
471 ++              char *ac_type = static_cast <char *> (data1);
472 ++              if (*ac_type == 'R') {
473 ++                      iClient* tmpUser = static_cast< iClient* >( data2 ) ;
474 ++                      networkData* tmpData = static_cast< networkData* >(tmpUser->getCustomData(this) ) ;
475 ++                      /* Lookup this user account, if its not there.. trouble */
476 ++                      sqlUser* theUser = getUserRecord(tmpUser->getAccount());
477 ++                      if (theUser)
478 ++                              {
479 ++                              tmpData->currentUser = theUser;
480 ++                              theUser->addAuthedClient(tmpUser);
481 ++                              }
482 ++              } else if (*ac_type == 'C') {
483 ++                      // server prefix, client prefix, username, password
484 ++                      char **param_list = static_cast <char **> (data2);
485 ++                      sqlUser* theUser = getUserRecord(param_list[2]);
486 ++                      strstream ac;
487 ++
488 ++                      LogDebugMessage("Checking account: user=%s pass=%s ok=%d susp=%d maxlog=%d/%d",
489 ++                              param_list[2],
490 ++                              param_list[3],
491 ++                              isPasswordRight(theUser, param_list[3]),
492 ++                              theUser->getFlag(sqlUser::F_GLOBAL_SUSPEND),
493 ++                              theUser->networkClientList.size() + 1,
494 ++                              theUser->getMaxLogins());
495 ++
496 ++                      ac << getCharYY() << " AC " << param_list[0];
497 ++                      
498 ++                      if (theUser && !theUser->getFlag(sqlUser::F_GLOBAL_SUSPEND) &&
499 ++                              isPasswordRight(theUser, param_list[3]) &&
500 ++                              theUser->networkClientList.size() + 1 <= theUser->getMaxLogins()) {
501 ++                              ac << " A ";
502 ++                      } else {
503 ++                              ac << " D ";
504 +                       }
505 ++
506 ++                      ac << param_list[1] << ends;
507 ++                      Write(ac);
508 ++                      delete[] ac.str();
509 ++              }
510 +               break;
511 +               }
512 +       case EVT_BURST_ACK:
513 +Index: src/msg_AC.cc
514 +===================================================================
515 +RCS file: /cvsroot/gnuworld/gnuworld/src/msg_AC.cc,v
516 +retrieving revision 1.1
517 +diff -u -r1.1 msg_AC.cc
518 +--- src/msg_AC.cc      12 Jan 2002 21:42:17 -0000      1.1
519 ++++ src/msg_AC.cc      12 Apr 2002 12:33:46 -0000
520 +@@ -14,23 +14,48 @@
521 +  * SOURCE AC TARGET ACCOUNT
522 +  * Eg:
523 +  * AXAAA AC BQrTd Gte
524 ++ *
525 ++ * AX AC BQrTd R Gte
526 ++ * BQ AC AX C BqrTd Gte :Gte's Pass
527 +  */
528 +-int xServer::MSG_AC( xParameters& Param )
529 ++int xServer::MSG_AC(xParameters &Param)
530 + {
531 + /*
532 +  * First, update this users information.
533 +  */
534
535 +-iClient* theClient = Network->findClient(Param[1]);
536 +-if(!theClient)
537 +-      {
538 +-              return 0;
539 +-      }
540 ++const char *numeric = NULL, *account = NULL;
541 ++static char *ac_type_C = "C";
542 ++static char *ac_type_R = "R";
543
544 +-theClient->setAccount(Param[2]);
545 ++if (Param.size() < 4) {
546 ++      numeric = Param[1];
547 ++      account = Param[2];
548 ++} else if (Param[2][0] == 'R') {
549 ++      numeric = Param[1];
550 ++      account = Param[3];
551 ++} else if (Param[2][0] == 'C') {
552 ++      const char *param_list[4];
553 ++      param_list[0] = Param[0];
554 ++      param_list[1] = Param[3];
555 ++      param_list[2] = Param[4];
556 ++      param_list[3] = Param[5];
557 ++      PostEvent(EVT_ACCOUNT, static_cast <void *> (ac_type_C), static_cast <void *> (param_list));
558 ++      return 0;
559 ++}
560 ++
561 ++if (!numeric || !account)
562 ++      return 0;
563 ++
564 ++iClient *theClient = Network->findClient(numeric);
565 ++if (!theClient)
566 ++      return 0;
567 ++
568 ++theClient->setAccount(account);
569 ++PostEvent(EVT_ACCOUNT, static_cast <void *> (ac_type_R), static_cast <void *> (theClient)) ;
570
571 +-PostEvent( EVT_ACCOUNT, static_cast< void* >( theClient ) ) ;
572 + return 0;
573 ++
574 + }
575
576 + } // namespace gnuworld