users.c

Go to the documentation of this file.
00001 /* Routines to maintain a list of online users.
00002  *
00003  * (C) 2003-2007 Anope Team
00004  * Contact us at info@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church. 
00010  * 
00011  * $Id: users.c 1295 2007-08-31 20:40:36Z drstein $
00012  *
00013  */
00014 
00015 #include "services.h"
00016 
00017 #define HASH(nick)  (((nick)[0]&31)<<5 | ((nick)[1]&31))
00018 User *userlist[1024];
00019 
00020 #define HASH2(nick) (((nick)[0]&31)<<5 | ((nick)[1]&31))
00021 Uid *uidlist[1024];
00022 
00023 int32 usercnt = 0, opcnt = 0;
00024 uint32 maxusercnt = 0;
00025 time_t maxusertime;
00026 
00027 /*************************************************************************/
00028 /*************************************************************************/
00029 
00030 /* Allocate a new User structure, fill in basic values, link it to the
00031  * overall list, and return it.  Always successful.
00032  */
00033 
00034 static User *new_user(const char *nick)
00035 {
00036     User *user, **list;
00037 
00038     user = scalloc(sizeof(User), 1);
00039     if (!nick)
00040         nick = "";
00041     strscpy(user->nick, nick, NICKMAX);
00042     list = &userlist[HASH(user->nick)];
00043     user->next = *list;
00044     if (*list)
00045         (*list)->prev = user;
00046     *list = user;
00047     user->na = findnick(nick);
00048     if (user->na)
00049         user->na->u = user;
00050     usercnt++;
00051     if (usercnt > maxusercnt) {
00052         maxusercnt = usercnt;
00053         maxusertime = time(NULL);
00054         if (LogMaxUsers)
00055             alog("user: New maximum user count: %d", maxusercnt);
00056     }
00057     user->isSuperAdmin = 0;     /* always set SuperAdmin to 0 for new users */
00058     user->nickTrack = NULL;     /* ensure no default tracking nick */
00059     return user;
00060 }
00061 
00062 /*************************************************************************/
00063 
00064 /* Change the nickname of a user, and move pointers as necessary. */
00065 
00066 static void change_user_nick(User * user, const char *nick)
00067 {
00068     User **list;
00069     int is_same;
00070 
00071     /* Sanity check to make sure we don't segfault */
00072     if (!user || !nick || !*nick) {
00073         return;
00074     }
00075 
00076     is_same = (!stricmp(user->nick, nick) ? 1 : 0);
00077 
00078     if (user->prev)
00079         user->prev->next = user->next;
00080     else
00081         userlist[HASH(user->nick)] = user->next;
00082     if (user->next)
00083         user->next->prev = user->prev;
00084     user->nick[1] = 0;          /* paranoia for zero-length nicks */
00085     strscpy(user->nick, nick, NICKMAX);
00086     list = &userlist[HASH(user->nick)];
00087     user->next = *list;
00088     user->prev = NULL;
00089     if (*list)
00090         (*list)->prev = user;
00091     *list = user;
00092 
00093     /* Only if old and new nick aren't the same; no need to waste time */
00094     if (!is_same) {
00095         if (user->na)
00096             user->na->u = NULL;
00097         user->na = findnick(nick);
00098         if (user->na)
00099             user->na->u = user;
00100     }
00101 }
00102 
00103 /*************************************************************************/
00104 
00105 void update_host(User * user)
00106 {
00107     if (user->na && (nick_identified(user)
00108                      || (!(user->na->nc->flags & NI_SECURE)
00109                          && nick_recognized(user)))) {
00110         if (user->na->last_usermask)
00111             free(user->na->last_usermask);
00112 
00113         user->na->last_usermask =
00114             smalloc(strlen(common_get_vident(user)) +
00115                     strlen(common_get_vhost(user)) + 2);
00116         sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user),
00117                 common_get_vhost(user));
00118     }
00119 
00120     if (debug)
00121         alog("debug: %s changes its host to %s", user->nick,
00122              common_get_vhost(user));
00123 }
00124 
00125 
00126 /*************************************************************************/
00127 
00128 /* Change the (virtual) hostname of a user. */
00129 
00130 void change_user_host(User * user, const char *host)
00131 {
00132     if (user->vhost)
00133         free(user->vhost);
00134     user->vhost = sstrdup(host);
00135 
00136     if (debug)
00137         alog("debug: %s changes its vhost to %s", user->nick, host);
00138 
00139 
00140 
00141     update_host(user);
00142 }
00143 
00144 /*************************************************************************/
00145 
00146 /* Change the realname of a user. */
00147 
00148 void change_user_realname(User * user, const char *realname)
00149 {
00150     if (user->realname)
00151         free(user->realname);
00152     user->realname = sstrdup(realname);
00153 
00154     if (user->na && (nick_identified(user)
00155                      || (!(user->na->nc->flags & NI_SECURE)
00156                          && nick_recognized(user)))) {
00157         if (user->na->last_realname)
00158             free(user->na->last_realname);
00159         user->na->last_realname = sstrdup(realname);
00160     }
00161 
00162     if (debug)
00163         alog("debug: %s changes its realname to %s", user->nick, realname);
00164 }
00165 
00166 
00167 /*************************************************************************/
00168 
00169 /* Change the username of a user. */
00170 
00171 void change_user_username(User * user, const char *username)
00172 {
00173     if (user->vident)
00174         free(user->vident);
00175     user->vident = sstrdup(username);
00176     if (user->na && (nick_identified(user)
00177                      || (!(user->na->nc->flags & NI_SECURE)
00178                          && nick_recognized(user)))) {
00179         if (user->na->last_usermask)
00180             free(user->na->last_usermask);
00181 
00182         user->na->last_usermask =
00183             smalloc(strlen(common_get_vident(user)) +
00184                     strlen(common_get_vhost(user)) + 2);
00185         sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user),
00186                 common_get_vhost(user));
00187     }
00188     if (debug)
00189         alog("debug: %s changes its username to %s", user->nick, username);
00190 }
00191 
00192 /*************************************************************************/
00193 
00194 /* Remove and free a User structure. */
00195 
00196 void delete_user(User * user)
00197 {
00198     struct u_chanlist *c, *c2;
00199     struct u_chaninfolist *ci, *ci2;
00200     char *realname;
00201 
00202     if (LogUsers) {
00203         realname = normalizeBuffer(user->realname);
00204         if (ircd->vhost) {
00205             alog("LOGUSERS: %s (%s@%s => %s) (%s) left the network (%s).",
00206                  user->nick, user->username, user->host,
00207                  (user->vhost ? user->vhost : "(none)"),
00208                  realname, user->server->name);
00209         } else {
00210             alog("LOGUSERS: %s (%s@%s) (%s) left the network (%s).",
00211                  user->nick, user->username, user->host,
00212                  realname, user->server->name);
00213         }
00214         free(realname);
00215     }
00216     send_event(EVENT_USER_LOGOFF, 1, user->nick);
00217 
00218     if (debug >= 2)
00219         alog("debug: delete_user() called");
00220     usercnt--;
00221     if (is_oper(user))
00222         opcnt--;
00223     if (debug >= 2)
00224         alog("debug: delete_user(): free user data");
00225     free(user->username);
00226     free(user->host);
00227     if (user->vhost)
00228         free(user->vhost);
00229     if (user->vident)
00230         free(user->vident);
00231     if (user->uid) {
00232         free(user->uid);
00233     }
00234     Anope_Free(user->realname);
00235     Anope_Free(user->hostip);
00236     if (debug >= 2) {
00237         alog("debug: delete_user(): remove from channels");
00238     }
00239     c = user->chans;
00240     while (c) {
00241         c2 = c->next;
00242         chan_deluser(user, c->chan);
00243         free(c);
00244         c = c2;
00245     }
00246     /* This called only here now */
00247     cancel_user(user);
00248     if (user->na)
00249         user->na->u = NULL;
00250     if (debug >= 2)
00251         alog("debug: delete_user(): free founder data");
00252     ci = user->founder_chans;
00253     while (ci) {
00254         ci2 = ci->next;
00255         free(ci);
00256         ci = ci2;
00257     }
00258 
00259     if (user->nickTrack)
00260         free(user->nickTrack);
00261 
00262     moduleCleanStruct(&user->moduleData);
00263 
00264     if (debug >= 2)
00265         alog("debug: delete_user(): delete from list");
00266     if (user->prev)
00267         user->prev->next = user->next;
00268     else
00269         userlist[HASH(user->nick)] = user->next;
00270     if (user->next)
00271         user->next->prev = user->prev;
00272     if (debug >= 2)
00273         alog("debug: delete_user(): free user structure");
00274     free(user);
00275     if (debug >= 2)
00276         alog("debug: delete_user() done");
00277 }
00278 
00279 /*************************************************************************/
00280 /*************************************************************************/
00281 
00282 /* Return statistics.  Pointers are assumed to be valid. */
00283 
00284 void get_user_stats(long *nusers, long *memuse)
00285 {
00286     long count = 0, mem = 0;
00287     int i;
00288     User *user;
00289     struct u_chanlist *uc;
00290     struct u_chaninfolist *uci;
00291 
00292     for (i = 0; i < 1024; i++) {
00293         for (user = userlist[i]; user; user = user->next) {
00294             count++;
00295             mem += sizeof(*user);
00296             if (user->username)
00297                 mem += strlen(user->username) + 1;
00298             if (user->host)
00299                 mem += strlen(user->host) + 1;
00300             if (ircd->vhost) {
00301                 if (user->vhost)
00302                     mem += strlen(user->vhost) + 1;
00303             }
00304             if (user->realname)
00305                 mem += strlen(user->realname) + 1;
00306             if (user->server->name)
00307                 mem += strlen(user->server->name) + 1;
00308             for (uc = user->chans; uc; uc = uc->next)
00309                 mem += sizeof(*uc);
00310             for (uci = user->founder_chans; uci; uci = uci->next)
00311                 mem += sizeof(*uci);
00312         }
00313     }
00314     *nusers = count;
00315     *memuse = mem;
00316 }
00317 
00318 /*************************************************************************/
00319 
00320 /* Find a user by nick.  Return NULL if user could not be found. */
00321 
00322 User *finduser(const char *nick)
00323 {
00324     User *user;
00325 
00326     if (!nick || !*nick) {
00327         if (debug) {
00328             alog("debug: finduser() called with NULL values");
00329         }
00330         return NULL;
00331     }
00332 
00333     if (debug >= 3)
00334         alog("debug: finduser(%p)", nick);
00335     user = userlist[HASH(nick)];
00336     while (user && stricmp(user->nick, nick) != 0)
00337         user = user->next;
00338     if (debug >= 3)
00339         alog("debug: finduser(%s) -> 0x%p", nick, (void *) user);
00340     return user;
00341 }
00342 
00343 
00344 /*************************************************************************/
00345 
00346 /* Iterate over all users in the user list.  Return NULL at end of list. */
00347 
00348 static User *current;
00349 static int next_index;
00350 
00351 User *firstuser(void)
00352 {
00353     next_index = 0;
00354     current = NULL;
00355     while (next_index < 1024 && current == NULL)
00356         current = userlist[next_index++];
00357     if (debug)
00358         alog("debug: firstuser() returning %s",
00359              current ? current->nick : "NULL (end of list)");
00360     return current;
00361 }
00362 
00363 User *nextuser(void)
00364 {
00365     if (current)
00366         current = current->next;
00367     if (!current && next_index < 1024) {
00368         while (next_index < 1024 && current == NULL)
00369             current = userlist[next_index++];
00370     }
00371     if (debug)
00372         alog("debug: nextuser() returning %s",
00373              current ? current->nick : "NULL (end of list)");
00374     return current;
00375 }
00376 
00377 User *find_byuid(const char *uid)
00378 {
00379     User *u, *next;
00380 
00381     if (!uid) {
00382         if (debug)
00383             alog("debug: find_byuid() called with NULL-value");
00384         return NULL;
00385     }
00386 
00387     u = first_uid();
00388     while (u) {
00389         next = next_uid();
00390         if (u->uid) {
00391             if (!stricmp(uid, u->uid)) {
00392                 return u;
00393             }
00394         }
00395         u = next;
00396     }
00397     return NULL;
00398 }
00399 
00400 static User *current_uid;
00401 static int next_index_uid;
00402 
00403 User *first_uid(void)
00404 {
00405     next_index_uid = 0;
00406     current_uid = NULL;
00407     while (next_index_uid < 1024 && current_uid == NULL) {
00408         current_uid = userlist[next_index_uid++];
00409     }
00410     if (debug >= 2) {
00411         alog("debug: first_uid() returning %s %s",
00412              current_uid ? current_uid->nick : "NULL (end of list)",
00413              current_uid ? current_uid->uid : "");
00414     }
00415     return current_uid;
00416 }
00417 
00418 User *next_uid(void)
00419 {
00420     if (current_uid)
00421         current_uid = current_uid->next;
00422     if (!current_uid && next_index_uid < 1024) {
00423         while (next_index_uid < 1024 && current_uid == NULL)
00424             current_uid = userlist[next_index_uid++];
00425     }
00426     if (debug >= 2) {
00427         alog("debug: next_uid() returning %s %s",
00428              current_uid ? current_uid->nick : "NULL (end of list)",
00429              current_uid ? current_uid->uid : "");
00430     }
00431     return current_uid;
00432 }
00433 
00434 Uid *new_uid(const char *nick, char *uid)
00435 {
00436     Uid *u, **list;
00437 
00438     u = scalloc(sizeof(Uid), 1);
00439     if (!nick || !uid) {
00440         return NULL;
00441     }
00442     strscpy(u->nick, nick, NICKMAX);
00443     list = &uidlist[HASH2(u->nick)];
00444     u->next = *list;
00445     if (*list)
00446         (*list)->prev = u;
00447     *list = u;
00448     u->uid = sstrdup(uid);
00449     return u;
00450 }
00451 
00452 Uid *find_uid(const char *nick)
00453 {
00454     Uid *u;
00455     int i;
00456 
00457     for (i = 0; i < 1024; i++) {
00458         for (u = uidlist[i]; u; u = u->next) {
00459             if (!stricmp(nick, u->nick)) {
00460                 return u;
00461             }
00462         }
00463     }
00464     return NULL;
00465 }
00466 
00467 Uid *find_nickuid(const char *uid)
00468 {
00469     Uid *u;
00470     int i;
00471 
00472     for (i = 0; i < 1024; i++) {
00473         for (u = uidlist[i]; u; u = u->next) {
00474             if (!stricmp(uid, u->uid)) {
00475                 return u;
00476             }
00477         }
00478     }
00479     return NULL;
00480 }
00481 
00482 /*************************************************************************/
00483 /*************************************************************************/
00484 
00485 /* Handle a server NICK command. */
00486 
00487 User *do_nick(const char *source, char *nick, char *username, char *host,
00488               char *server, char *realname, time_t ts, uint32 svid,
00489               uint32 ip, char *vhost, char *uid)
00490 {
00491     User *user = NULL;
00492 
00493     char *tmp = NULL;
00494     NickAlias *old_na;          /* Old nick rec */
00495     int nc_changed = 1;         /* Did nick core change? */
00496     int status = 0;             /* Status to apply */
00497     char mask[USERMAX + HOSTMAX + 2];
00498     char *logrealname;
00499 
00500     if (!*source) {
00501         char ipbuf[16];
00502         struct in_addr addr;
00503 
00504         if (ircd->nickvhost) {
00505             if (vhost) {
00506                 if (!strcmp(vhost, "*")) {
00507                     vhost = NULL;
00508                     if (debug)
00509                         alog("debug: new user with no vhost in NICK command: %s", nick);
00510                 }
00511             }
00512         }
00513 
00514         /* This is a new user; create a User structure for it. */
00515         if (debug)
00516             alog("debug: new user: %s", nick);
00517 
00518         if (ircd->nickip) {
00519             addr.s_addr = htonl(ip);
00520             ntoa(addr, ipbuf, sizeof(ipbuf));
00521         }
00522 
00523 
00524         if (LogUsers) {
00528             if (realname) {
00529                 tmp = strchr(realname, '%');
00530                 while (tmp) {
00531                     *tmp = '-';
00532                     tmp = strchr(realname, '%');
00533                 }
00534             }
00535             logrealname = normalizeBuffer(realname);
00536 
00541             if (ircd->nickvhost) {
00542                 if (ircd->nickip) {
00543                     alog("LOGUSERS: %s (%s@%s => %s) (%s) [%s] connected to the network (%s).", nick, username, host, (vhost ? vhost : "none"), logrealname, ipbuf, server);
00544                 } else {
00545                     alog("LOGUSERS: %s (%s@%s => %s) (%s) connected to the network (%s).", nick, username, host, (vhost ? vhost : "none"), logrealname, server);
00546                 }
00547             } else {
00548                 if (ircd->nickip) {
00549                     alog("LOGUSERS: %s (%s@%s) (%s) [%s] connected to the network (%s).", nick, username, host, logrealname, ipbuf, server);
00550                 } else {
00551                     alog("LOGUSERS: %s (%s@%s) (%s) connected to the network (%s).", nick, username, host, logrealname, server);
00552                 }
00553             }
00554             Anope_Free(logrealname);
00555         }
00556 
00557         /* We used to ignore the ~ which a lot of ircd's use to indicate no
00558          * identd response.  That caused channel bans to break, so now we
00559          * just take what the server gives us.  People are still encouraged
00560          * to read the RFCs and stop doing anything to usernames depending
00561          * on the result of an identd lookup.
00562          */
00563 
00564         /* First check for AKILLs. */
00565         /* DONT just return null if its an akill match anymore - yes its more efficent to, however, now that ircd's are
00566          * starting to use things like E/F lines, we cant be 100% sure the client will be removed from the network :/
00567          * as such, create a user_struct, and if the client is removed, we'll delete it again when the QUIT notice
00568          * comes in from the ircd.
00569          **/
00570         if (check_akill(nick, username, host, vhost, ipbuf)) {
00571 /*            return NULL; */
00572         }
00573 
00578         /* don't akill on netmerges -Certus */
00579         if (is_sync(findserver(servlist, server))
00580             && checkDefCon(DEFCON_AKILL_NEW_CLIENTS)) {
00581             strncpy(mask, "*@", 3);
00582             strncat(mask, host, HOSTMAX);
00583             alog("DEFCON: adding akill for %s", mask);
00584             add_akill(NULL, mask, s_OperServ,
00585                       time(NULL) + dotime(DefConAKILL),
00586                       DefConAkillReason ? DefConAkillReason :
00587                       "DEFCON AKILL");
00588             if (check_akill(nick, username, host, vhost, ipbuf)) {
00589 /*            return NULL; */
00590             }
00591         }
00592 
00593         /* SGLINE */
00594         if (ircd->sgline) {
00595             if (check_sgline(nick, realname))
00596                 return NULL;
00597         }
00598 
00599         /* SQLINE */
00600         if (ircd->sqline) {
00601             if (check_sqline(nick, 0))
00602                 return NULL;
00603         }
00604 
00605         /* SZLINE */
00606         if (ircd->szline && ircd->nickip) {
00607             if (check_szline(nick, ipbuf))
00608                 return NULL;
00609         }
00610         /* Now check for session limits */
00611         if (LimitSessions && !add_session(nick, host, ipbuf))
00612             return NULL;
00613 
00614         /* Allocate User structure and fill it in. */
00615         user = new_user(nick);
00616         user->username = sstrdup(username);
00617         user->host = sstrdup(host);
00618         user->server = findserver(servlist, server);
00619         user->realname = sstrdup(realname);
00620         user->timestamp = ts;
00621         user->my_signon = time(NULL);
00622         user->vhost = vhost ? sstrdup(vhost) : sstrdup(host);
00623         if (uid) {
00624             user->uid = sstrdup(uid);   /* p10/ts6 stuff */
00625         } else {
00626             user->uid = NULL;
00627         }
00628         user->vident = sstrdup(username);
00629         /* We now store the user's ip in the user_ struct,
00630          * because we will use it in serveral places -- DrStein */
00631         if (ircd->nickip) {
00632             user->hostip = sstrdup(ipbuf);
00633         } else {
00634             user->hostip = NULL;
00635         }
00636 
00637         if (svid == 0) {
00638             display_news(user, NEWS_LOGON);
00639             display_news(user, NEWS_RANDOM);
00640         }
00641 
00642         if (svid == ts && user->na) {
00643             /* Timestamp and svid match, and nick is registered; automagically identify the nick */
00644             user->svid = svid;
00645             user->na->status |= NS_IDENTIFIED;
00646             check_memos(user);
00647             nc_changed = 0;
00648 
00649             /* Start nick tracking if available */
00650             if (NSNickTracking)
00651                 nsStartNickTracking(user);
00652 
00653         } else if (svid != 1) {
00654             /* Resets the svid because it doesn't match */
00655             user->svid = 1;
00656 
00657             anope_cmd_svid_umode(user->nick, user->timestamp);
00658 
00659         } else {
00660             user->svid = 1;
00661         }
00662         send_event(EVENT_NEWNICK, 1, nick);
00663 
00664     } else {
00665         /* An old user changing nicks. */
00666         if (UseTS6)
00667             user = find_byuid(source);
00668 
00669         if (!user)
00670             user = finduser(source);
00671 
00672         if (!user) {
00673             alog("user: NICK from nonexistent nick %s", source);
00674             return NULL;
00675         }
00676         user->isSuperAdmin = 0; /* Dont let people nick change and stay SuperAdmins */
00677         if (debug)
00678             alog("debug: %s changes nick to %s", source, nick);
00679 
00680         if (LogUsers) {
00681             logrealname = normalizeBuffer(user->realname);
00682             if (ircd->vhost) {
00683                 alog("LOGUSERS: %s (%s@%s => %s) (%s) changed nick to %s (%s).", user->nick, user->username, user->host, (user->vhost ? user->vhost : "(none)"), logrealname, nick, user->server->name);
00684             } else {
00685                 alog("LOGUSERS: %s (%s@%s) (%s) changed nick to %s (%s).",
00686                      user->nick, user->username, user->host, logrealname,
00687                      nick, user->server->name);
00688             }
00689             if (logrealname) {
00690                 free(logrealname);
00691             }
00692         }
00693 
00694         user->timestamp = ts;
00695 
00696         if (stricmp(nick, user->nick) == 0) {
00697             /* No need to redo things */
00698             change_user_nick(user, nick);
00699             nc_changed = 0;
00700         } else {
00701             /* Update this only if nicks aren't the same */
00702             user->my_signon = time(NULL);
00703 
00704             old_na = user->na;
00705             if (old_na) {
00706                 if (nick_recognized(user))
00707                     user->na->last_seen = time(NULL);
00708                 status = old_na->status & NS_TRANSGROUP;
00709                 cancel_user(user);
00710             }
00711 
00712             change_user_nick(user, nick);
00713             send_event(EVENT_CHANGE_NICK, 1, nick);
00714 
00715             if ((old_na ? old_na->nc : NULL) ==
00716                 (user->na ? user->na->nc : NULL))
00717                 nc_changed = 0;
00718 
00719             if (!nc_changed && (user->na))
00720                 user->na->status |= status;
00721             else {
00722                 anope_cmd_nc_change(user);
00723             }
00724         }
00725 
00726         if (ircd->sqline) {
00727             if (!is_oper(user) && check_sqline(user->nick, 1))
00728                 return NULL;
00729         }
00730 
00731     }                           /* if (!*source) */
00732 
00733     /* Check for nick tracking to bypass identification */
00734     if (NSNickTracking && nsCheckNickTracking(user)) {
00735         user->na->status |= NS_IDENTIFIED;
00736         nc_changed = 0;
00737     }
00738 
00739     if (nc_changed || !nick_recognized(user)) {
00740         if (validate_user(user))
00741             check_memos(user);
00742 
00743     } else {
00744         if (nick_identified(user)) {
00745             char tsbuf[16];
00746             user->na->last_seen = time(NULL);
00747 
00748             if (user->na->last_usermask)
00749                 free(user->na->last_usermask);
00750             user->na->last_usermask =
00751                 smalloc(strlen(common_get_vident(user)) +
00752                         strlen(common_get_vhost(user)) + 2);
00753             sprintf(user->na->last_usermask, "%s@%s",
00754                     common_get_vident(user), common_get_vhost(user));
00755 
00756             snprintf(tsbuf, sizeof(tsbuf), "%lu",
00757                      (unsigned long int) user->timestamp);
00758             anope_cmd_svid_umode2(user, tsbuf);
00759 
00760             alog("%s: %s!%s@%s automatically identified for nick %s",
00761                  s_NickServ, user->nick, user->username,
00762                  user->host, user->nick);
00763         }
00764     }
00765 
00766     /* Bahamut sets -r on every nick changes, so we must test it even if nc_changed == 0 */
00767     if (ircd->check_nick_id) {
00768         if (nick_identified(user)) {
00769             char tsbuf[16];
00770             snprintf(tsbuf, sizeof(tsbuf), "%lu",
00771                      (unsigned long int) user->timestamp);
00772             anope_cmd_svid_umode3(user, tsbuf);
00773         }
00774     }
00775 
00776     return user;
00777 }
00778 
00779 /*************************************************************************/
00780 
00781 /* Handle a MODE command for a user.
00782  *  av[0] = nick to change mode for
00783  *  av[1] = modes
00784  */
00785 
00786 void do_umode(const char *source, int ac, char **av)
00787 {
00788     User *user;
00789 
00790     user = finduser(av[0]);
00791     if (!user) {
00792         alog("user: MODE %s for nonexistent nick %s: %s", av[1], av[0],
00793              merge_args(ac, av));
00794         return;
00795     }
00796 
00797     anope_set_umode(user, ac - 1, &av[1]);
00798 }
00799 
00800 /* Handle a UMODE2 command for a user.
00801  *  av[0] = modes
00802  */
00803 
00804 void do_umode2(const char *source, int ac, char **av)
00805 {
00806     User *user;
00807 
00808     user = finduser(source);
00809     if (!user) {
00810         alog("user: MODE %s for nonexistent nick %s: %s", av[0], source,
00811              merge_args(ac, av));
00812         return;
00813     }
00814 
00815     anope_set_umode(user, ac, &av[0]);
00816 }
00817 
00818 /*************************************************************************/
00819 
00820 /* Handle a QUIT command.
00821  *  av[0] = reason
00822  */
00823 
00824 void do_quit(const char *source, int ac, char **av)
00825 {
00826     User *user;
00827     NickAlias *na;
00828 
00829     user = finduser(source);
00830     if (!user) {
00831         alog("user: QUIT from nonexistent user %s: %s", source,
00832              merge_args(ac, av));
00833         return;
00834     }
00835     if (debug) {
00836         alog("debug: %s quits", source);
00837     }
00838     if ((na = user->na) && (!(na->status & NS_VERBOTEN))
00839         && (!(na->nc->flags & NI_SUSPENDED))
00840         && (na->status & (NS_IDENTIFIED | NS_RECOGNIZED))) {
00841         na->last_seen = time(NULL);
00842         if (na->last_quit)
00843             free(na->last_quit);
00844         na->last_quit = *av[0] ? sstrdup(av[0]) : NULL;
00845     }
00846     if (LimitSessions) {
00847         del_session(user->host);
00848     }
00849     delete_user(user);
00850 }
00851 
00852 /*************************************************************************/
00853 
00854 /* Handle a KILL command.
00855  *  av[0] = nick being killed
00856  *  av[1] = reason
00857  */
00858 
00859 void do_kill(char *nick, char *msg)
00860 {
00861     User *user;
00862     NickAlias *na;
00863 
00864     user = finduser(nick);
00865     if (!user) {
00866         if (debug) {
00867             alog("debug: KILL of nonexistent nick: %s", nick);
00868         }
00869         return;
00870     }
00871     if (debug) {
00872         alog("debug: %s killed", nick);
00873     }
00874     if ((na = user->na) && (!(na->status & NS_VERBOTEN))
00875         && (!(na->nc->flags & NI_SUSPENDED))
00876         && (na->status & (NS_IDENTIFIED | NS_RECOGNIZED))) {
00877         na->last_seen = time(NULL);
00878         if (na->last_quit)
00879             free(na->last_quit);
00880         na->last_quit = *msg ? sstrdup(msg) : NULL;
00881 
00882     }
00883     if (LimitSessions) {
00884         del_session(user->host);
00885     }
00886     delete_user(user);
00887 }
00888 
00889 /*************************************************************************/
00890 /*************************************************************************/
00891 
00892 /* Is the given user protected from kicks and negative mode changes? */
00893 
00894 int is_protected(User * user)
00895 {
00896     if (ircd->protectedumode) {
00897         return (user->mode & ircd->protectedumode);
00898     } else {
00899         return 0;
00900     }
00901 }
00902 
00903 /*************************************************************************/
00904 
00905 /* Is the given nick an oper? */
00906 
00907 int is_oper(User * user)
00908 {
00909     if (user) {
00910         return (user->mode & anope_get_oper_mode());
00911     } else {
00912         return 0;
00913     }
00914 }
00915 
00916 /*************************************************************************/
00917 /*************************************************************************/
00918 
00919 /* Is the given user ban-excepted? */
00920 int is_excepted(ChannelInfo * ci, User * user)
00921 {
00922     int count, i;
00923     int isexcepted = 0;
00924     char **excepts;
00925 
00926     if (!ci->c)
00927         return 0;
00928 
00929     if (!ircd->except) {
00930         return 0;
00931     }
00932 
00933     count = ci->c->exceptcount;
00934     excepts = scalloc(sizeof(char *) * count, 1);
00935     memcpy(excepts, ci->c->excepts, sizeof(char *) * count);
00936 
00937     for (i = 0; i < count; i++) {
00938         if (match_usermask(excepts[i], user)
00939             || match_userip(excepts[i], user, user->hostip)) {
00940             isexcepted = 1;
00941             break;
00942         }
00943     }
00944     free(excepts);
00945     return isexcepted;
00946 }
00947 
00948 /*************************************************************************/
00949 
00950 /* Is the given MASK ban-excepted? */
00951 int is_excepted_mask(ChannelInfo * ci, char *mask)
00952 {
00953     int count, i;
00954     int isexcepted = 0;
00955     char **excepts;
00956 
00957     if (!ci->c)
00958         return 0;
00959 
00960     if (!ircd->except) {
00961         return 0;
00962     }
00963 
00964     count = ci->c->exceptcount;
00965     excepts = scalloc(sizeof(char *) * count, 1);
00966     memcpy(excepts, ci->c->excepts, sizeof(char *) * count);
00967 
00968     for (i = 0; i < count; i++) {
00969         if (match_wild_nocase(excepts[i], mask)) {
00970             isexcepted = 1;
00971         }
00972     }
00973     free(excepts);
00974     return isexcepted;
00975 }
00976 
00977 
00978 /*************************************************************************/
00979 
00980 /* Does the user's usermask match the given mask (either nick!user@host or
00981  * just user@host)?
00982  */
00983 
00984 int match_usermask(const char *mask, User * user)
00985 {
00986     char *mask2;
00987     char *nick, *username, *host;
00988     int result;
00989 
00990     if (!mask || !*mask) {
00991         return 0;
00992     }
00993 
00994     mask2 = sstrdup(mask);
00995 
00996     if (strchr(mask2, '!')) {
00997         nick = strtok(mask2, "!");
00998         username = strtok(NULL, "@");
00999     } else {
01000         nick = NULL;
01001         username = strtok(mask2, "@");
01002     }
01003     host = strtok(NULL, "");
01004     if (!username || !host) {
01005         free(mask2);
01006         return 0;
01007     }
01008 
01009     if (nick) {
01010         result = match_wild_nocase(nick, user->nick)
01011             && match_wild_nocase(username, user->username)
01012             && (match_wild_nocase(host, user->host)
01013                 || match_wild_nocase(host, user->vhost));
01014     } else {
01015         result = match_wild_nocase(username, user->username)
01016             && (match_wild_nocase(host, user->host)
01017                 || match_wild_nocase(host, user->vhost));
01018     }
01019 
01020     free(mask2);
01021     return result;
01022 }
01023 
01024 
01025 /*************************************************************************/
01026 
01027 /* simlar to match_usermask, except here we pass the host as the IP */
01028 
01029 int match_userip(const char *mask, User * user, char *iphost)
01030 {
01031     char *mask2;
01032     char *nick, *username, *host;
01033     int result;
01034 
01035     if (!mask || !*mask) {
01036         return 0;
01037     }
01038 
01039     mask2 = sstrdup(mask);
01040 
01041     if (strchr(mask2, '!')) {
01042         nick = strtok(mask2, "!");
01043         username = strtok(NULL, "@");
01044     } else {
01045         nick = NULL;
01046         username = strtok(mask2, "@");
01047     }
01048     host = strtok(NULL, "");
01049     if (!username || !host) {
01050         free(mask2);
01051         return 0;
01052     }
01053 
01054     if (nick) {
01055         result = match_wild_nocase(nick, user->nick)
01056             && match_wild_nocase(username, user->username)
01057             && (match_wild_nocase(host, iphost)
01058                 || match_wild_nocase(host, user->vhost));
01059     } else {
01060         result = match_wild_nocase(username, user->username)
01061             && (match_wild_nocase(host, iphost)
01062                 || match_wild_nocase(host, user->vhost));
01063     }
01064 
01065     free(mask2);
01066     return result;
01067 }
01068 
01069 /*************************************************************************/
01070 
01071