00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "services.h"
00016 #include "pseudo.h"
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 #define HASH(host) (((host)[0]&31)<<5 | ((host)[1]&31))
00059
00060 Session *sessionlist[1024];
00061 int32 nsessions = 0;
00062
00063 Exception *exceptions = NULL;
00064 int16 nexceptions = 0;
00065
00066
00067
00068
00069
00070 void get_session_stats(long *nrec, long *memuse)
00071 {
00072 Session *session;
00073 long mem;
00074 int i;
00075
00076 mem = sizeof(Session) * nsessions;
00077 for (i = 0; i < 1024; i++) {
00078 for (session = sessionlist[i]; session; session = session->next) {
00079 mem += strlen(session->host) + 1;
00080 }
00081 }
00082
00083 *nrec = nsessions;
00084 *memuse = mem;
00085 }
00086
00087 void get_exception_stats(long *nrec, long *memuse)
00088 {
00089 long mem;
00090 int i;
00091
00092 mem = sizeof(Exception) * nexceptions;
00093 for (i = 0; i < nexceptions; i++) {
00094 mem += strlen(exceptions[i].mask) + 1;
00095 mem += strlen(exceptions[i].reason) + 1;
00096 }
00097 *nrec = nexceptions;
00098 *memuse = mem;
00099 }
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 int do_session(User * u)
00115 {
00116 Session *session;
00117 Exception *exception;
00118 char *cmd = strtok(NULL, " ");
00119 char *param1 = strtok(NULL, " ");
00120 int mincount;
00121 int i;
00122
00123 if (!LimitSessions) {
00124 notice_lang(s_OperServ, u, OPER_SESSION_DISABLED);
00125 return MOD_CONT;
00126 }
00127
00128 if (!cmd)
00129 cmd = "";
00130
00131 if (stricmp(cmd, "LIST") == 0) {
00132 if (!param1) {
00133 syntax_error(s_OperServ, u, "SESSION",
00134 OPER_SESSION_LIST_SYNTAX);
00135
00136 } else if ((mincount = atoi(param1)) <= 1) {
00137 notice_lang(s_OperServ, u, OPER_SESSION_INVALID_THRESHOLD);
00138
00139 } else {
00140 notice_lang(s_OperServ, u, OPER_SESSION_LIST_HEADER, mincount);
00141 notice_lang(s_OperServ, u, OPER_SESSION_LIST_COLHEAD);
00142 for (i = 0; i < 1024; i++) {
00143 for (session = sessionlist[i]; session;
00144 session = session->next) {
00145 if (session->count >= mincount)
00146 notice_lang(s_OperServ, u,
00147 OPER_SESSION_LIST_FORMAT,
00148 session->count, session->host);
00149 }
00150 }
00151 }
00152 } else if (stricmp(cmd, "VIEW") == 0) {
00153 if (!param1) {
00154 syntax_error(s_OperServ, u, "SESSION",
00155 OPER_SESSION_VIEW_SYNTAX);
00156
00157 } else {
00158 session = findsession(param1);
00159 if (!session) {
00160 notice_lang(s_OperServ, u, OPER_SESSION_NOT_FOUND, param1);
00161 } else {
00162 exception = find_host_exception(param1);
00163
00164 notice_lang(s_OperServ, u, OPER_SESSION_VIEW_FORMAT,
00165 param1, session->count,
00166 exception ? exception->
00167 limit : DefSessionLimit);
00168 }
00169 }
00170
00171 } else {
00172 syntax_error(s_OperServ, u, "SESSION", OPER_SESSION_SYNTAX);
00173 }
00174 return MOD_CONT;
00175 }
00176
00177
00178
00179
00180
00181 Session *findsession(const char *host)
00182 {
00183 Session *session;
00184 int i;
00185
00186 if (!host) {
00187 return NULL;
00188 }
00189
00190 for (i = 0; i < 1024; i++) {
00191 for (session = sessionlist[i]; session; session = session->next) {
00192 if (stricmp(host, session->host) == 0) {
00193 return session;
00194 }
00195 }
00196 }
00197
00198 return NULL;
00199 }
00200
00201
00202
00203
00204
00205
00206 int add_session(char *nick, char *host, char *hostip)
00207 {
00208 Session *session, **list;
00209 Exception *exception;
00210 int sessionlimit = 0;
00211
00212 session = findsession(host);
00213
00214 if (session) {
00215 exception = find_hostip_exception(host, hostip);
00216
00217 if (checkDefCon(DEFCON_REDUCE_SESSION)) {
00218 sessionlimit =
00219 exception ? exception->limit : DefConSessionLimit;
00220 } else {
00221 sessionlimit = exception ? exception->limit : DefSessionLimit;
00222 }
00223
00224 if (sessionlimit != 0 && session->count >= sessionlimit) {
00225 if (SessionLimitExceeded)
00226 notice(s_OperServ, nick, SessionLimitExceeded, host);
00227 if (SessionLimitDetailsLoc)
00228 notice(s_OperServ, nick, "%s", SessionLimitDetailsLoc);
00229
00230
00231
00232
00233 kill_user(s_OperServ, nick, "Session limit exceeded");
00234
00235 session->hits++;
00236 if (MaxSessionKill && session->hits >= MaxSessionKill) {
00237 char akillmask[BUFSIZE];
00238 snprintf(akillmask, sizeof(akillmask), "*@%s", host);
00239 add_akill(NULL, akillmask, s_OperServ,
00240 time(NULL) + SessionAutoKillExpiry,
00241 "Session limit exceeded");
00242 anope_cmd_global(s_OperServ,
00243 "Added a temporary AKILL for \2%s\2 due to excessive connections",
00244 akillmask);
00245 }
00246 return 0;
00247 } else {
00248 session->count++;
00249 return 1;
00250 }
00251 }
00252
00253 nsessions++;
00254 session = scalloc(sizeof(Session), 1);
00255 session->host = sstrdup(host);
00256 list = &sessionlist[HASH(session->host)];
00257 session->next = *list;
00258 if (*list)
00259 (*list)->prev = session;
00260 *list = session;
00261 session->count = 1;
00262
00263 return 1;
00264 }
00265
00266 void del_session(const char *host)
00267 {
00268 Session *session;
00269
00270 if (!LimitSessions) {
00271 if (debug) {
00272 alog("debug: del_session called when LimitSessions is disabled");
00273 }
00274 return;
00275 }
00276
00277 if (!host || !*host) {
00278 if (debug) {
00279 alog("debug: del_session called with NULL values");
00280 }
00281 return;
00282 }
00283
00284 if (debug >= 2)
00285 alog("debug: del_session() called");
00286
00287 session = findsession(host);
00288
00289 if (!session) {
00290 if (debug) {
00291 anope_cmd_global(s_OperServ,
00292 "WARNING: Tried to delete non-existant session: \2%s",
00293 host);
00294 alog("session: Tried to delete non-existant session: %s",
00295 host);
00296 }
00297 return;
00298 }
00299
00300 if (session->count > 1) {
00301 session->count--;
00302 return;
00303 }
00304
00305 if (session->prev)
00306 session->prev->next = session->next;
00307 else
00308 sessionlist[HASH(session->host)] = session->next;
00309 if (session->next)
00310 session->next->prev = session->prev;
00311
00312 if (debug >= 2)
00313 alog("debug: del_session(): free session structure");
00314
00315 free(session->host);
00316 free(session);
00317
00318 nsessions--;
00319
00320 if (debug >= 2)
00321 alog("debug: del_session() done");
00322 }
00323
00324
00325
00326
00327
00328
00329 void expire_exceptions(void)
00330 {
00331 int i;
00332 time_t now = time(NULL);
00333
00334 for (i = 0; i < nexceptions; i++) {
00335 if (exceptions[i].expires == 0 || exceptions[i].expires > now)
00336 continue;
00337 if (WallExceptionExpire)
00338 anope_cmd_global(s_OperServ,
00339 "Session limit exception for %s has expired.",
00340 exceptions[i].mask);
00341 free(exceptions[i].mask);
00342 free(exceptions[i].reason);
00343 nexceptions--;
00344 memmove(exceptions + i, exceptions + i + 1,
00345 sizeof(Exception) * (nexceptions - i));
00346 exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
00347 i--;
00348 }
00349 }
00350
00351
00352 Exception *find_host_exception(const char *host)
00353 {
00354 int i;
00355
00356 for (i = 0; i < nexceptions; i++) {
00357 if ((match_wild_nocase(exceptions[i].mask, host))) {
00358 return &exceptions[i];
00359 }
00360 }
00361
00362 return NULL;
00363 }
00364
00365
00366
00367 Exception *find_hostip_exception(const char *host, const char *hostip)
00368 {
00369 int i;
00370
00371 for (i = 0; i < nexceptions; i++) {
00372 if ((match_wild_nocase(exceptions[i].mask, host))
00373 || ((ircd->nickip && hostip)
00374 && (match_wild_nocase(exceptions[i].mask, hostip)))) {
00375 return &exceptions[i];
00376 }
00377 }
00378
00379 return NULL;
00380 }
00381
00382
00383
00384
00385
00386 #define SAFE(x) do { \
00387 if ((x) < 0) { \
00388 if (!forceload) \
00389 fatal("Read error on %s", ExceptionDBName); \
00390 nexceptions = i; \
00391 break; \
00392 } \
00393 } while (0)
00394
00395 void load_exceptions()
00396 {
00397 dbFILE *f;
00398 int i;
00399 uint16 n;
00400 uint16 tmp16;
00401 uint32 tmp32;
00402
00403 if (!
00404 (f = open_db(s_OperServ, ExceptionDBName, "r", EXCEPTION_VERSION)))
00405 return;
00406 switch (i = get_file_version(f)) {
00407 case 9:
00408 case 8:
00409 case 7:
00410 SAFE(read_int16(&n, f));
00411 nexceptions = n;
00412 exceptions = scalloc(sizeof(Exception) * nexceptions, 1);
00413 if (!nexceptions) {
00414 close_db(f);
00415 return;
00416 }
00417 for (i = 0; i < nexceptions; i++) {
00418 SAFE(read_string(&exceptions[i].mask, f));
00419 SAFE(read_int16(&tmp16, f));
00420 exceptions[i].limit = tmp16;
00421 SAFE(read_buffer(exceptions[i].who, f));
00422 SAFE(read_string(&exceptions[i].reason, f));
00423 SAFE(read_int32(&tmp32, f));
00424 exceptions[i].time = tmp32;
00425 SAFE(read_int32(&tmp32, f));
00426 exceptions[i].expires = tmp32;
00427 }
00428 break;
00429
00430 default:
00431 fatal("Unsupported version (%d) on %s", i, ExceptionDBName);
00432 }
00433
00434 close_db(f);
00435 }
00436
00437 #undef SAFE
00438
00439
00440
00441 #define SAFE(x) do { \
00442 if ((x) < 0) { \
00443 restore_db(f); \
00444 log_perror("Write error on %s", ExceptionDBName); \
00445 if (time(NULL) - lastwarn > WarningTimeout) { \
00446 anope_cmd_global(NULL, "Write error on %s: %s", ExceptionDBName, \
00447 strerror(errno)); \
00448 lastwarn = time(NULL); \
00449 } \
00450 return; \
00451 } \
00452 } while (0)
00453
00454 void save_exceptions()
00455 {
00456 dbFILE *f;
00457 int i;
00458 static time_t lastwarn = 0;
00459
00460 if (!
00461 (f = open_db(s_OperServ, ExceptionDBName, "w", EXCEPTION_VERSION)))
00462 return;
00463 SAFE(write_int16(nexceptions, f));
00464 for (i = 0; i < nexceptions; i++) {
00465 SAFE(write_string(exceptions[i].mask, f));
00466 SAFE(write_int16(exceptions[i].limit, f));
00467 SAFE(write_buffer(exceptions[i].who, f));
00468 SAFE(write_string(exceptions[i].reason, f));
00469 SAFE(write_int32(exceptions[i].time, f));
00470 SAFE(write_int32(exceptions[i].expires, f));
00471 }
00472 close_db(f);
00473 }
00474
00475 #undef SAFE
00476
00477
00478
00479 void save_rdb_exceptions()
00480 {
00481 #ifdef USE_RDB
00482 int i;
00483 Exception *e;
00484
00485 if (!rdb_open())
00486 return;
00487 if (rdb_tag_table("anope_os_exceptions") == 0) {
00488 alog("Unable to tag table 'anope_os_exceptions' - Exception RDB save failed.");
00489 return;
00490 }
00491 for (i = 0; i < nexceptions; i++) {
00492 e = &exceptions[i];
00493 if (rdb_save_exceptions(e) == 0) {
00494 alog("Unable to save Exception '%s' - Exception RDB save failed.", e->mask);
00495 return;
00496 }
00497 }
00498 if (rdb_clean_table("anope_os_exceptions") == 0) {
00499 alog("Unable to clean table 'anope_os_exceptions' - Exception RDB save failed.");
00500 return;
00501 }
00502 rdb_close();
00503 #endif
00504 }
00505
00506
00507
00508
00509
00510 int exception_add(User * u, const char *mask, const int limit,
00511 const char *reason, const char *who,
00512 const time_t expires)
00513 {
00514 int i;
00515
00516
00517 for (i = 0; i < nexceptions; i++) {
00518 if (!stricmp(mask, exceptions[i].mask)) {
00519 if (exceptions[i].limit != limit) {
00520 exceptions[i].limit = limit;
00521 if (u)
00522 notice_lang(s_OperServ, u, OPER_EXCEPTION_CHANGED,
00523 mask, exceptions[i].limit);
00524 return -2;
00525 } else {
00526 if (u)
00527 notice_lang(s_OperServ, u, OPER_EXCEPTION_EXISTS,
00528 mask);
00529 return -1;
00530 }
00531 }
00532 }
00533
00534 nexceptions++;
00535 exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
00536
00537 exceptions[nexceptions - 1].mask = sstrdup(mask);
00538 exceptions[nexceptions - 1].limit = limit;
00539 exceptions[nexceptions - 1].reason = sstrdup(reason);
00540 exceptions[nexceptions - 1].time = time(NULL);
00541 strscpy(exceptions[nexceptions - 1].who, who, NICKMAX);
00542 exceptions[nexceptions - 1].expires = expires;
00543 exceptions[nexceptions - 1].num = nexceptions - 1;
00544
00545 return 1;
00546 }
00547
00548
00549
00550 static int exception_del(const int index)
00551 {
00552 if (index < 0 || index >= nexceptions)
00553 return 0;
00554
00555 free(exceptions[index].mask);
00556 free(exceptions[index].reason);
00557 nexceptions--;
00558 memmove(exceptions + index, exceptions + index + 1,
00559 sizeof(Exception) * (nexceptions - index));
00560 exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
00561
00562 return 1;
00563 }
00564
00565
00566
00567
00568
00569
00570
00571 static int exception_del_callback(User * u, int num, va_list args)
00572 {
00573 int i;
00574 int *last = va_arg(args, int *);
00575
00576 *last = num;
00577 for (i = 0; i < nexceptions; i++) {
00578 if (num - 1 == exceptions[i].num)
00579 break;
00580 }
00581 if (i < nexceptions)
00582 return exception_del(i);
00583 else
00584 return 0;
00585 }
00586
00587 static int exception_list(User * u, const int index, int *sent_header)
00588 {
00589 if (index < 0 || index >= nexceptions)
00590 return 0;
00591 if (!*sent_header) {
00592 notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_HEADER);
00593 notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_COLHEAD);
00594 *sent_header = 1;
00595 }
00596 notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_FORMAT, index + 1,
00597 exceptions[index].limit, exceptions[index].mask);
00598 return 1;
00599 }
00600
00601 static int exception_list_callback(User * u, int num, va_list args)
00602 {
00603 int *sent_header = va_arg(args, int *);
00604
00605 return exception_list(u, num - 1, sent_header);
00606 }
00607
00608 static int exception_view(User * u, const int index, int *sent_header)
00609 {
00610 char timebuf[32], expirebuf[256];
00611 struct tm tm;
00612 time_t t = time(NULL);
00613
00614 if (index < 0 || index >= nexceptions)
00615 return 0;
00616 if (!*sent_header) {
00617 notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_HEADER);
00618 *sent_header = 1;
00619 }
00620
00621 tm = *localtime(exceptions[index].time ? &exceptions[index].time : &t);
00622 strftime_lang(timebuf, sizeof(timebuf),
00623 u, STRFTIME_SHORT_DATE_FORMAT, &tm);
00624
00625 expire_left(u->na, expirebuf, sizeof(expirebuf),
00626 exceptions[index].expires);
00627
00628 notice_lang(s_OperServ, u, OPER_EXCEPTION_VIEW_FORMAT,
00629 index + 1, exceptions[index].mask,
00630 *exceptions[index].who ?
00631 exceptions[index].who : "<unknown>",
00632 timebuf, expirebuf, exceptions[index].limit,
00633 exceptions[index].reason);
00634 return 1;
00635 }
00636
00637 static int exception_view_callback(User * u, int num, va_list args)
00638 {
00639 int *sent_header = va_arg(args, int *);
00640
00641 return exception_view(u, num - 1, sent_header);
00642 }
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664 int do_exception(User * u)
00665 {
00666 char *cmd = strtok(NULL, " ");
00667 char *mask, *reason, *expiry, *limitstr;
00668 int limit, expires;
00669 int i;
00670 int x;
00671
00672 if (!LimitSessions) {
00673 notice_lang(s_OperServ, u, OPER_EXCEPTION_DISABLED);
00674 return MOD_CONT;
00675 }
00676
00677 if (!cmd)
00678 cmd = "";
00679
00680 if (stricmp(cmd, "ADD") == 0) {
00681 if (nexceptions >= 32767) {
00682 notice_lang(s_OperServ, u, OPER_EXCEPTION_TOO_MANY);
00683 return MOD_CONT;
00684 }
00685
00686 mask = strtok(NULL, " ");
00687 if (mask && *mask == '+') {
00688 expiry = mask;
00689 mask = strtok(NULL, " ");
00690 } else {
00691 expiry = NULL;
00692 }
00693 limitstr = strtok(NULL, " ");
00694 reason = strtok(NULL, "");
00695
00696 if (!reason) {
00697 syntax_error(s_OperServ, u, "EXCEPTION",
00698 OPER_EXCEPTION_ADD_SYNTAX);
00699 return MOD_CONT;
00700 }
00701
00702 expires = expiry ? dotime(expiry) : ExceptionExpiry;
00703 if (expires < 0) {
00704 notice_lang(s_OperServ, u, BAD_EXPIRY_TIME);
00705 return MOD_CONT;
00706 } else if (expires > 0) {
00707 expires += time(NULL);
00708 }
00709
00710 limit = (limitstr && isdigit(*limitstr)) ? atoi(limitstr) : -1;
00711
00712 if (limit < 0 || limit > MaxSessionLimit) {
00713 notice_lang(s_OperServ, u, OPER_EXCEPTION_INVALID_LIMIT,
00714 MaxSessionLimit);
00715 return MOD_CONT;
00716
00717 } else {
00718 if (strchr(mask, '!') || strchr(mask, '@')) {
00719 notice_lang(s_OperServ, u,
00720 OPER_EXCEPTION_INVALID_HOSTMASK);
00721 return MOD_CONT;
00722 }
00723
00724 x = exception_add(u, mask, limit, reason, u->nick, expires);
00725
00726 if (x == 1) {
00727 notice_lang(s_OperServ, u, OPER_EXCEPTION_ADDED, mask,
00728 limit);
00729 }
00730
00731 if (readonly)
00732 notice_lang(s_OperServ, u, READ_ONLY_MODE);
00733 }
00734 } else if (stricmp(cmd, "DEL") == 0) {
00735 mask = strtok(NULL, " ");
00736
00737 if (!mask) {
00738 syntax_error(s_OperServ, u, "EXCEPTION",
00739 OPER_EXCEPTION_DEL_SYNTAX);
00740 return MOD_CONT;
00741 }
00742
00743 if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
00744 int count, deleted, last = -1;
00745 deleted =
00746 process_numlist(mask, &count, exception_del_callback, u,
00747 &last);
00748 if (!deleted) {
00749 if (count == 1) {
00750 notice_lang(s_OperServ, u,
00751 OPER_EXCEPTION_NO_SUCH_ENTRY, last);
00752 } else {
00753 notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);
00754 }
00755 } else if (deleted == 1) {
00756 notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED_ONE);
00757 } else {
00758 notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED_SEVERAL,
00759 deleted);
00760 }
00761 } else {
00762 int deleted = 0;
00763
00764 for (i = 0; i < nexceptions; i++) {
00765 if (stricmp(mask, exceptions[i].mask) == 0) {
00766 exception_del(i);
00767 notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED,
00768 mask);
00769 deleted = 1;
00770 break;
00771 }
00772 }
00773 if (!deleted && i == nexceptions)
00774 notice_lang(s_OperServ, u, OPER_EXCEPTION_NOT_FOUND, mask);
00775 }
00776
00777
00778
00779
00780
00781
00782 for (i = 0; i < nexceptions; i++)
00783 exceptions[i].num = i;
00784
00785 if (readonly)
00786 notice_lang(s_OperServ, u, READ_ONLY_MODE);
00787
00788 } else if (stricmp(cmd, "MOVE") == 0) {
00789 Exception *exception;
00790 char *n1str = strtok(NULL, " ");
00791 char *n2str = strtok(NULL, " ");
00792 int n1, n2;
00793
00794 if (!n2str) {
00795 syntax_error(s_OperServ, u, "EXCEPTION",
00796 OPER_EXCEPTION_MOVE_SYNTAX);
00797 return MOD_CONT;
00798 }
00799
00800 n1 = atoi(n1str) - 1;
00801 n2 = atoi(n2str) - 1;
00802
00803 if ((n1 >= 0 && n1 < nexceptions) && (n2 >= 0 && n2 < nexceptions)
00804 && (n1 != n2)) {
00805 exception = scalloc(sizeof(Exception), 1);
00806 memcpy(exception, &exceptions[n1], sizeof(Exception));
00807
00808 if (n1 < n2) {
00809
00810 memmove(&exceptions[n1], &exceptions[n1 + 1],
00811 sizeof(Exception) * (n2 - n1));
00812 memmove(&exceptions[n2], exception, sizeof(Exception));
00813 } else {
00814
00815 memmove(&exceptions[n2 + 1], &exceptions[n2],
00816 sizeof(Exception) * (n1 - n2));
00817 memmove(&exceptions[n2], exception, sizeof(Exception));
00818 }
00819
00820 free(exception);
00821
00822 notice_lang(s_OperServ, u, OPER_EXCEPTION_MOVED,
00823 exceptions[n1].mask, n1 + 1, n2 + 1);
00824
00825
00826 for (i = 0; i < nexceptions; i++)
00827 exceptions[i].num = i;
00828
00829 if (readonly)
00830 notice_lang(s_OperServ, u, READ_ONLY_MODE);
00831 } else {
00832 syntax_error(s_OperServ, u, "EXCEPTION",
00833 OPER_EXCEPTION_MOVE_SYNTAX);
00834 }
00835 } else if (stricmp(cmd, "LIST") == 0) {
00836 int sent_header = 0;
00837 expire_exceptions();
00838 mask = strtok(NULL, " ");
00839 if (mask && strspn(mask, "1234567890,-") == strlen(mask)) {
00840 process_numlist(mask, NULL, exception_list_callback, u,
00841 &sent_header);
00842 } else {
00843 for (i = 0; i < nexceptions; i++) {
00844 if (!mask || match_wild_nocase(mask, exceptions[i].mask))
00845 exception_list(u, i, &sent_header);
00846 }
00847 }
00848 if (!sent_header)
00849 notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);
00850
00851 } else if (stricmp(cmd, "VIEW") == 0) {
00852 int sent_header = 0;
00853 expire_exceptions();
00854 mask = strtok(NULL, " ");
00855 if (mask && strspn(mask, "1234567890,-") == strlen(mask)) {
00856 process_numlist(mask, NULL, exception_view_callback, u,
00857 &sent_header);
00858 } else {
00859 for (i = 0; i < nexceptions; i++) {
00860 if (!mask || match_wild_nocase(mask, exceptions[i].mask))
00861 exception_view(u, i, &sent_header);
00862 }
00863 }
00864 if (!sent_header)
00865 notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);
00866
00867 } else {
00868 syntax_error(s_OperServ, u, "EXCEPTION", OPER_EXCEPTION_SYNTAX);
00869 }
00870 return MOD_CONT;
00871 }
00872
00873