00001
00015
00016
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 #include "services.h"
00048 #include "chanserv.h"
00049 #include "nickserv.h"
00050 #include "macro.h"
00051 #include "queue.h"
00052 #include "hash.h"
00053 #include "db.h"
00054 #include "log.h"
00055 #include "email.h"
00056 #include "interp.h"
00057 #include "chantrig.h"
00058 #include "hash/md5pw.h"
00059
00060 #define ARGLEN 150
00061 #define DEFIFZERO(value, default) ((value) ? (value) : (default))
00062
00066 const int TOPIC_MAX = 350;
00067
00068 ChanList *firstChan = NULL;
00069 ChanList *lastChan = NULL;
00070 RegChanList *firstRegChan = NULL;
00071 RegChanList *lastRegChan = NULL;
00072
00073 const char *GetAuthChKey(const char*, const char*, time_t, u_int32_t);
00074 const char *PrintPass(u_char pI[], char enc);
00075 char *urlEncode(const char *);
00076
00077
00078
00079
00080 void createGhostChannel(char *);
00081 void deleteGhostChannel(char *);
00082 void deleteTimedGhostChannel(char *);
00083
00084 static cmd_return do_chanop(services_cmd_id, UserList *,
00085 RegChanList * chan, const char *nick,
00086 int level);
00087 static cmd_return do_chanop_del(UserList * isfrom, RegChanList * chan,
00088 const char *cTargetNick, int tarLevel);
00089 static cmd_return do_chanop_add(UserList * isfrom, RegChanList * chan,
00090 const char *cTargetNick, int tarLevel);
00091 static cmd_return do_chanop_list(UserList * isfrom, RegChanList * chan,
00092 const char *cTargetNick, int tarLevel);
00093
00095 typedef struct _cs_settbl__
00096 {
00097 char *cmd;
00098 cmd_return(*func) (struct _cs_settbl__ *, UserList *, RegChanList *,
00099 char **, int);
00100 int aclvl;
00101 size_t xoff;
00102 const char *optname;
00103 unsigned long int optlen;
00104 }
00105 cs_settbl_t;
00106
00107 cmd_return cs_set_passwd(cs_settbl_t *, UserList *, RegChanList *, char **,
00108 int);
00109 cmd_return cs_set_memolvl(cs_settbl_t *, UserList *, RegChanList *,
00110 char **, int);
00111 cmd_return cs_set_founder(cs_settbl_t *, UserList *, RegChanList *,
00112 char **, int);
00113 cmd_return cs_set_string(cs_settbl_t *, UserList *, RegChanList *, char **,
00114 int);
00115 cmd_return cs_set_fixed(cs_settbl_t *, UserList *, RegChanList *, char **,
00116 int);
00117 cmd_return cs_set_bool(cs_settbl_t *, UserList *, RegChanList *, char **,
00118 int);
00119 cmd_return cs_set_mlock(cs_settbl_t *, UserList *, RegChanList *, char **,
00120 int);
00121 cmd_return cs_set_restrict(cs_settbl_t *, UserList *, RegChanList *,
00122 char **, int);
00123 cmd_return cs_set_topiclock(cs_settbl_t *, UserList *, RegChanList *,
00124 char **, int);
00125 cmd_return cs_set_encrypt(cs_settbl_t *, UserList *, RegChanList *,
00126 char **, int);
00127
00128
00130 interp::service_cmd_t chanserv_commands[] = {
00131
00132 { "help", cs_help, 0, LOG_NO, 0, 2},
00133 { "info", cs_info, 0, LOG_NO, 0, 5},
00134 { "acc*", cs_access, 0, LOG_NO, CMD_MATCH, 3},
00135 { "chanop", cs_chanop, 0, LOG_NO, CMD_REG, 3},
00136 { "aop", cs_chanop, 0, LOG_NO, CMD_REG, 3},
00137 { "maop", cs_chanop, 0, LOG_NO, CMD_REG, 3},
00138 { "msop", cs_chanop, 0, LOG_NO, CMD_REG, 3},
00139 { "sop", cs_chanop, 0, LOG_NO, CMD_REG, 3},
00140 { "founder", cs_chanop, 0, LOG_NO, CMD_REG, 3},
00141 { "mfounder", cs_chanop, 0, LOG_NO, CMD_REG, 3},
00142 { "akick", cs_akick, 0, LOG_NO, CMD_REG, 3},
00143 { "register", cs_register, 0, LOG_NO, CMD_REG, 20},
00144 { "identify", cs_identify, 0, LOG_NO, CMD_REG, 15},
00145 { "id", cs_identify, 0, LOG_NO, CMD_REG, 15},
00146 { "addop", cs_addop, 0, LOG_NO, CMD_REG, 10},
00147 { "addak*", cs_addak, 0, LOG_NO, CMD_REG | CMD_MATCH, 10},
00148 { "delop", cs_addop, 0, LOG_NO, CMD_REG, 10},
00149 { "mdeop", cs_mdeop, 0, LOG_NO, CMD_REG, 10},
00150 { "mkick", cs_mkick, 0, LOG_NO, CMD_REG, 10},
00151 { "wipeak*", cs_wipeak, 0, LOG_NO, CMD_REG | CMD_MATCH, 10},
00152 { "wipeop", cs_wipeop, OOPER|ODMOD, LOG_OK, CMD_REG | CMD_MATCH, 10},
00153 { "delak*", cs_delak, 0, LOG_NO, CMD_REG | CMD_MATCH, 10},
00154 { "listop*", cs_listop, 0, LOG_NO, CMD_REG | CMD_MATCH, 5},
00155 { "listak*", cs_listak, 0, LOG_NO, CMD_REG | CMD_MATCH, 5},
00156 { "delete", cs_delete, OOPER|OCBANDEL, LOG_NO, CMD_REG, 0},
00157 { "drop", cs_drop, 0, LOG_NO, CMD_REG, 20},
00158 { "op", cs_op, 0, LOG_NO, 0, 20},
00159 { "deop", cs_deop, 0, LOG_NO, CMD_REG, 20},
00160 { "clist", cs_clist, 0, LOG_NO, CMD_REG, 5},
00161 { "banish", cs_banish, 0, LOG_NO, CMD_REG, 0},
00162 { "clean", cs_clean, 0, LOG_NO, CMD_REG, 3},
00163 { "close", cs_close, 0, LOG_NO, CMD_REG, 0},
00164 { "hold", cs_hold, 0, LOG_NO, CMD_REG, 0},
00165 { "mark", cs_mark, 0, LOG_NO, CMD_REG, 0},
00166 { "m*lock", cs_modelock, 0, LOG_NO, CMD_REG | CMD_MATCH, 3},
00167 { "restrict", cs_restrict, 0, LOG_NO, CMD_REG, 3},
00168 { "t*lock", cs_topiclock, 0, LOG_NO, CMD_REG | CMD_MATCH, 3},
00169 { "set", cs_set, 0, LOG_NO, CMD_REG, 3},
00170 { "sendpass", cs_getpass, 0, LOG_NO, CMD_REG, 5},
00171 { "getpass", cs_getpass, 0, LOG_NO, CMD_REG, 5},
00172 { "setpass", cs_setpass, 0, LOG_NO, CMD_REG, 5},
00173 { "setrealpass", cs_setrealpass, OOPER, LOG_OK, CMD_REG, 5},
00174 #ifndef NOGRPCMD
00175 { "getrealpass",cs_getrealpass, 0, LOG_NO, CMD_REG, 5},
00176 #endif
00177 { "save", cs_save, 0, LOG_NO, CMD_REG, 15},
00178 { "unban", cs_unban, 0, LOG_NO, CMD_REG, 5},
00179 { "invite", cs_invite, 0, LOG_NO, CMD_REG, 3},
00180 { "list", cs_list, 0, LOG_NO, CMD_REG, 5},
00181 { "whois", cs_whois, 0, LOG_NO, CMD_REG, 5},
00182 { "log", cs_log, OOPER, LOG_NO, CMD_REG, 1},
00183 { "dmod", cs_dmod, OOPER|ODMOD, LOG_OK, CMD_REG, 3},
00184 { "trigger", cs_trigger, OROOT, LOG_DB, CMD_REG, 5},
00185 { NULL }
00186 };
00187
00189 static struct {
00190 int lev;
00191 const char *v[3];
00192 }
00193 oplev_table[] = {
00194 { 0, {"User", "user", "User" }},
00195 { 1, {"MAOP(1)", "miniop(1)", "MiniOp(1)" }},
00196 { 2, {"MAOP(2)", "miniop-", "MiniOp(2)" }},
00197 { MAOP,{"MAOP", "miniop", "MiniOp" }},
00198 { 4, {"MAOP(4)", "miniop(4)", "MiniOp(4)" }},
00199 { AOP, {"AOP", "aop", "AutoOp" }},
00200 { 6, {"AOP(6)", "aop(6)", "AutoOp(6)" }},
00201 { 7, {"AOP(7)", "aop(7)", "AutoOp(7)" }},
00202 { MSOP,{"MSOP", "msop", "MiniSop" }},
00203 { 9, {"MSOP(9)", "msop(9)", "MiniSop(9)" }},
00204 { SOP, {"SOP", "sop", "SuperOp" }},
00205 { 11, {"SOP(11)", "sop(11)", "SuperOp(11)" }},
00206 { 12, {"SOP(12)", "sop(12)", "SuperOp(12)" }},
00207 { MFOUNDER, {"MFOUNDER","mfounder","MiniFounder" }},
00208 { 14, {"MFOUNDER(14)","mfounder(14)", "MiniFounder(14)"}},
00209 { FOUNDER, {"FOUNDER", "founder", "Founder" }},
00210 { 16, { "UNDEFINED", "undefined", "Undefined" }},
00211 };
00212
00213
00214
00215
00216
00217
00228 int BadPwChan(UserList *nick, RegChanList *target)
00229 {
00230 if (nick == NULL || target == NULL)
00231 return 0;
00232
00233 if (nick->badpws < UCHAR_MAX)
00234 nick->badpws++;
00235 if (target->badpws < UCHAR_MAX)
00236 target->badpws++;
00237
00238 if ((nick->badpws > CPW_TH_SENDER_1 && target->badpws > CPW_TH_TARGET_1)
00239 || (nick->badpws > CPW_TH_SENDER_2 && target->badpws > CPW_TH_TARGET_2)
00240 || (nick->badpws > CPW_TH_SENDER_3 && target->badpws > CPW_TH_TARGET_3))
00241 {
00242 sSend(":%s GLOBOPS :Possible password guess attempt %s (%u) -> %s (%u)",
00243 ChanServ, nick->nick, (u_int)nick->badpws,
00244 target->name, (u_int)target->badpws);
00245 }
00246
00247 if (addFlood(nick, FLOODVAL_BADPW))
00248 return 1;
00249 return 0;
00250 }
00251
00256 void GoodPwChan(UserList *nick, RegChanList *target)
00257 {
00258 if (nick == NULL || target == NULL)
00259 return;
00260
00261 if (target->badpws > 0) {
00262 sSend(":%s NOTICE %s :%s had %d failed password attempts since last identify.",
00263 ChanServ, nick->nick, target->name, target->badpws);
00264 }
00265
00266 target->badpws = 0;
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00285 void addChan(ChanList * newchan)
00286 {
00287 HashKeyVal hashEnt = getHashKey(newchan->name) % CHANHASHSIZE;
00288
00289 if (getChanData(newchan->name)) {
00290 FREE(newchan);
00291 return;
00292 }
00293
00294 if (firstChan == NULL) {
00295 firstChan = newchan;
00296 newchan->previous = NULL;
00297 } else {
00298 lastChan->next = newchan;
00299 newchan->previous = lastChan;
00300 }
00301 lastChan = newchan;
00302 newchan->next = NULL;
00303
00304 if (!ChanHash[hashEnt].chan) {
00305 ChanHash[hashEnt].chan = newchan;
00306 newchan->hashprev = NULL;
00307 } else {
00308 ChanHash[hashEnt].lastchan->hashnext = newchan;
00309 newchan->hashprev = ChanHash[hashEnt].lastchan;
00310 }
00311
00312 ChanHash[hashEnt].lastchan = newchan;
00313 newchan->hashnext = NULL;
00314 }
00315
00326 void addRegChan(RegChanList * newchan)
00327 {
00328 HashKeyVal hashEnt = getHashKey(newchan->name) % CHANHASHSIZE;
00329
00330 if (getRegChanData(newchan->name)) {
00331 freeRegChan(newchan);
00332 return;
00333 }
00334
00335 if (!firstRegChan) {
00336 firstRegChan = newchan;
00337 newchan->previous = NULL;
00338 } else {
00339 lastRegChan->next = newchan;
00340 newchan->previous = lastRegChan;
00341 }
00342 lastRegChan = newchan;
00343 newchan->next = NULL;
00344
00345 if (!RegChanHash[hashEnt].chan) {
00346 RegChanHash[hashEnt].chan = newchan;
00347 newchan->hashprev = NULL;
00348 } else {
00349 RegChanHash[hashEnt].lastchan->hashnext = newchan;
00350 newchan->hashprev = RegChanHash[hashEnt].lastchan;
00351 }
00352
00353 RegChanHash[hashEnt].lastchan = newchan;
00354 newchan->hashnext = NULL;
00355 }
00356
00371 void addChanUser(ChanList * channel, cNickList * newnick)
00372 {
00373 HashKeyVal hashEnt;
00374 if (newnick == NULL) {
00375 return;
00376 }
00377
00378 if (channel->firstUser == NULL) {
00379 channel->firstUser = newnick;
00380 newnick->previous = NULL;
00381 } else {
00382 channel->lastUser->next = newnick;
00383 newnick->previous = channel->lastUser;
00384 }
00385
00386 channel->lastUser = newnick;
00387 newnick->next = NULL;
00388
00389 hashEnt = getHashKey(newnick->person->nick) % CHANUSERHASHSIZE;
00390
00391 if (channel->users[hashEnt].item == NULL) {
00392 channel->users[hashEnt].item = newnick;
00393 newnick->hashprev = NULL;
00394 } else {
00395 channel->users[hashEnt].lastitem->hashnext = newnick;
00396 newnick->hashprev = channel->users[hashEnt].lastitem;
00397 }
00398
00399 channel->users[hashEnt].lastitem = newnick;
00400 newnick->hashnext = NULL;
00401
00402 }
00403
00404
00405
00418 void addChanBan(ChanList * channel, cBanList * item)
00419 {
00420 if (channel->firstBan == NULL) {
00421 channel->firstBan = item;
00422 item->previous = NULL;
00423 } else {
00424 channel->lastBan->next = item;
00425 item->previous = channel->lastBan;
00426 }
00427
00428 channel->lastBan = item;
00429 item->next = NULL;
00430 }
00431
00432
00446 void addChanAkick(RegChanList * channel, cAkickList * item)
00447 {
00448 if (channel->firstAkick == NULL) {
00449 channel->firstAkick = item;
00450 item->previous = NULL;
00451 } else {
00452 channel->lastAkick->next = item;
00453 item->previous = channel->lastAkick;
00454 }
00455
00456 channel->lastAkick = item;
00457 item->next = NULL;
00458 channel->akicks++;
00459 indexAkickItems(channel);
00460 }
00461
00476 void addChanOp(RegChanList * channel, cAccessList * item)
00477 {
00478 HashKeyVal hashEnt;
00479
00480 if (channel == NULL || item == NULL)
00481 return;
00482
00483 if (channel->firstOp == NULL) {
00484 channel->firstOp = item;
00485 item->previous = NULL;
00486 } else {
00487 channel->lastOp->next = item;
00488 item->previous = channel->lastOp;
00489 }
00490
00491 channel->lastOp = item;
00492 item->next = NULL;
00493 hashEnt = ( item->nickId.getHashKey() % OPHASHSIZE );
00494
00495 if (channel->op[hashEnt].item == NULL) {
00496 channel->op[hashEnt].item = item;
00497 item->hashprev = NULL;
00498 } else {
00499 channel->op[hashEnt].lastitem->hashnext = item;
00500 item->hashprev = channel->op[hashEnt].lastitem;
00501 }
00502
00503 channel->op[hashEnt].lastitem = item;
00504 item->hashnext = NULL;
00505 channel->ops++;
00506 indexOpItems(channel);
00507 }
00508
00519 void delChan(ChanList * killme)
00520 {
00521 HashKeyVal hashEnt;
00522 ChanList *tmpchan;
00523
00524 if (killme == NULL)
00525 return;
00526
00527 if (killme->previous)
00528 killme->previous->next = killme->next;
00529 else
00530 firstChan = killme->next;
00531
00532 if (killme->next)
00533 killme->next->previous = killme->previous;
00534 else
00535 lastChan = killme->previous;
00536
00537 hashEnt = getHashKey(killme->name) % CHANHASHSIZE;
00538 for (tmpchan = ChanHash[hashEnt].chan; tmpchan;
00539 tmpchan = tmpchan->hashnext) {
00540 if (tmpchan == killme) {
00541 if (killme->hashprev)
00542 killme->hashprev->hashnext = killme->hashnext;
00543 else
00544 ChanHash[hashEnt].chan = killme->hashnext;
00545
00546 if (killme->hashnext)
00547 killme->hashnext->hashprev = killme->hashprev;
00548 else
00549 ChanHash[hashEnt].lastchan = killme->hashprev;
00550 }
00551 }
00552
00553 FREE(killme);
00554 }
00555
00569 void delRegChan(RegChanList * killme)
00570 {
00571 HashKeyVal hashEnt;
00572 RegChanList *tmpchan;
00573 RegNickIdMap *ptrMap;
00574
00575 if (killme == NULL)
00576 return;
00577
00578 if (killme->previous)
00579 killme->previous->next = killme->next;
00580 else
00581 firstRegChan = killme->next;
00582
00583 if (killme->next)
00584 killme->next->previous = killme->previous;
00585 else
00586 lastRegChan = killme->previous;
00587
00588 hashEnt = getHashKey(killme->name) % CHANHASHSIZE;
00589 for (tmpchan = RegChanHash[hashEnt].chan; tmpchan;
00590 tmpchan = tmpchan->hashnext) {
00591 if (tmpchan == killme) {
00592 if (killme->hashprev)
00593 killme->hashprev->hashnext = killme->hashnext;
00594 else
00595 RegChanHash[hashEnt].chan = killme->hashnext;
00596
00597 if (killme->hashnext)
00598 killme->hashnext->hashprev = killme->hashprev;
00599 else
00600 RegChanHash[hashEnt].lastchan = killme->hashprev;
00601 }
00602 }
00603
00604 ptrMap = killme->founderId.getIdMap();
00605
00606 if (ptrMap && ptrMap->nick) {
00607 ptrMap->nick->chans--;
00608 }
00609
00610 freeRegChan(killme);
00611 }
00612
00623 void freeRegChan(RegChanList * killme)
00624 {
00625 if (killme->id.nick)
00626 FREE(killme->id.nick);
00627 if (killme->url)
00628 FREE(killme->url);
00629 if (killme->autogreet)
00630 FREE(killme->autogreet);
00631 if (killme->markby)
00632 FREE(killme->markby);
00633 FREE(killme);
00634 }
00635
00636
00650 void delChanUser(ChanList * channel, cNickList * nick, int doCleanChan)
00651 {
00652 HashKeyVal hashEnt, i = 0;
00653 cNickList *tmpnick;
00654
00655 if (nick == NULL || channel == NULL)
00656 return;
00657
00658 if (nick->previous != NULL)
00659 nick->previous->next = nick->next;
00660 else
00661 channel->firstUser = nick->next;
00662
00663 if (nick->next != NULL)
00664 nick->next->previous = nick->previous;
00665 else
00666 channel->lastUser = nick->previous;
00667
00668 hashEnt = getHashKey(nick->person->nick) % CHANUSERHASHSIZE;
00669
00670 for (tmpnick = channel->users[hashEnt].item; tmpnick;
00671 tmpnick = tmpnick->hashnext) {
00672 if (tmpnick == nick) {
00673 if (nick->hashprev != NULL)
00674 nick->hashprev->hashnext = nick->hashnext;
00675 else
00676 channel->users[hashEnt].item = nick->hashnext;
00677
00678 if (nick->hashnext != NULL)
00679 nick->hashnext->hashprev = nick->hashprev;
00680 else
00681 channel->users[hashEnt].lastitem = nick->hashprev;
00682 }
00683 }
00684
00685
00686 if (nick->person)
00687 for (i = 0; i < NICKCHANHASHSIZE; i++)
00688 if (nick->person->chan[i] == channel)
00689 nick->person->chan[i] = NULL;
00690 FREE(nick);
00691
00692
00693
00694
00695
00696 if (doCleanChan && channel->firstUser == NULL)
00697 delChan(channel);
00698 }
00699
00708 void delChanBan(ChanList * channel, cBanList * item)
00709 {
00710 if (item->previous)
00711 item->previous->next = item->next;
00712 else
00713 channel->firstBan = item->next;
00714
00715 if (item->next)
00716 item->next->previous = item->previous;
00717 else
00718 channel->lastBan = item->previous;
00719
00720 FREE(item);
00721 }
00722
00723
00732 void delChanAkick(RegChanList * channel, cAkickList * item)
00733 {
00734 if (item->previous)
00735 item->previous->next = item->next;
00736 else
00737 channel->firstAkick = item->next;
00738
00739 if (item->next)
00740 item->next->previous = item->previous;
00741 else
00742 channel->lastAkick = item->previous;
00743
00744 FREE(item);
00745 channel->akicks--;
00746 indexAkickItems(channel);
00747 }
00748
00759 void delChanOp(RegChanList * channel, cAccessList * item)
00760 {
00761 HashKeyVal hashEnt;
00762 cAccessList *tmpnick;
00763
00764 if (item->previous)
00765 item->previous->next = item->next;
00766 else
00767 channel->firstOp = item->next;
00768
00769 if (item->next)
00770 item->next->previous = item->previous;
00771 else
00772 channel->lastOp = item->previous;
00773
00774 hashEnt = item->nickId.getHashKey() % OPHASHSIZE;
00775 for (tmpnick = channel->op[hashEnt].item; tmpnick;
00776 tmpnick = tmpnick->hashnext) {
00777 if (tmpnick == item) {
00778 if (item->hashprev)
00779 item->hashprev->hashnext = item->hashnext;
00780 else
00781 channel->op[hashEnt].item = item->hashnext;
00782
00783 if (item->hashnext)
00784 item->hashnext->hashprev = item->hashprev;
00785 else
00786 channel->op[hashEnt].lastitem = item->hashprev;
00787 }
00788 }
00789
00790 FREE(item);
00791 channel->ops--;
00792 indexOpItems(channel);
00793 }
00794
00803 ChanList *getChanData(char *name)
00804 {
00805 HashKeyVal hashEnt;
00806 if (!name)
00807 return NULL;
00808
00809 hashEnt = getHashKey(name) % CHANHASHSIZE;
00810
00811 if (ChanHash[hashEnt].chan == NULL)
00812 return NULL;
00813 else {
00814 ChanList *tmpchan;
00815
00816 for (tmpchan = ChanHash[hashEnt].chan; tmpchan;
00817 tmpchan = tmpchan->hashnext) {
00818 if (!strcasecmp(tmpchan->name, name))
00819 return tmpchan;
00820 }
00821
00822 return NULL;
00823 }
00824 }
00825
00835 RegChanList *getRegChanData(char *name)
00836 {
00837 HashKeyVal hashEnt;
00838 if (name == NULL)
00839 return NULL;
00840
00841 hashEnt = getHashKey(name) % CHANHASHSIZE;
00842
00843 if (RegChanHash[hashEnt].chan == NULL)
00844 return NULL;
00845 else {
00846 RegChanList *tmpchan;
00847 for (tmpchan = RegChanHash[hashEnt].chan; tmpchan;
00848 tmpchan = tmpchan->hashnext) {
00849 if (!strcasecmp(tmpchan->name, name))
00850 return tmpchan;
00851 }
00852 return NULL;
00853 }
00854 }
00855
00861 char ChanGetEnc(RegChanList *rcl)
00862 {
00863 if (rcl)
00864 return ((rcl->flags & CENCRYPT) ? '$' : '@');
00865 return '@';
00866 }
00867
00873 char ChanGetIdent(RegChanList *rcl)
00874 {
00875 if (rcl)
00876 return ((rcl->flags & CIDENT) ? 1 : 0);
00877 return 0;
00878 }
00879
00891 cNickList *getChanUserData(ChanList * chan, UserList * data)
00892 {
00893 HashKeyVal hashEnt;
00894 cNickList *tmpnick;
00895
00896 if (data == NULL || chan == NULL)
00897 return NULL;
00898
00899 hashEnt = getHashKey(data->nick) % CHANUSERHASHSIZE;
00900
00901 if (chan->users[hashEnt].item == NULL)
00902 return NULL;
00903
00904 for (tmpnick = chan->users[hashEnt].item; tmpnick != NULL;
00905 tmpnick = tmpnick->hashnext) if (tmpnick->person != NULL
00906 && tmpnick->person == data)
00907 return tmpnick;
00908
00909 return NULL;
00910 }
00911
00919 #define process_op_item(x) { \
00920 if (x) { \
00921 if (checkAccessNick) \
00922 { \
00923 strncpyzt(checkAccessNick, tmpNickName, NICKLEN); \
00924 } \
00925 if (highest < (x)->uflags) { \
00926 highest = (x)->uflags; \
00927 } \
00928 } \
00929 }
00930
00950 int getMiscChanOp(RegChanList * chan, char *nick, int id,
00951 char *checkAccessNick)
00952 {
00953 int highest = 0;
00954 UserList *tmp;
00955 cAccessList *tmpnick;
00956 const char *tmpNickName;
00957
00958 if (!nick || !chan)
00959 return 0;
00960
00961 tmp = getNickData(nick);
00962
00963
00964 if (!tmp || ((chan->flags & (CBANISH | CCLOSE)) && !isOper(tmp)))
00965 return 0;
00966
00967
00968 if (isFounder(chan, tmp)) {
00969 if (checkAccessNick)
00970 strncpyzt(checkAccessNick, "founder(PW)", NICKLEN);
00971 return FOUNDER;
00972 }
00973
00974 if (id) {
00975
00976 UserList *check = getNickData(nick);
00977 RegNickList *reg2;
00978 if (check && check->reg) {
00979 if (isIdentified(check, check->reg)) {
00980 tmpnick = getChanOpData(chan, nick);
00981
00982 if (tmpnick) {
00983 tmpNickName = tmpnick->nickId.getNick();
00984 if (tmpNickName)
00985 process_op_item(tmpnick);
00986 }
00987 }
00988 }
00989 if (check && check->id.nick
00990 && (reg2 = getRegNickData(check->id.nick))) {
00991 if (isIdentified(check, reg2)) {
00992 tmpnick = getChanOpData(chan, reg2->nick);
00993 if (tmpnick) {
00994 tmpNickName = (tmpnick->nickId.getNick());
00995 if (tmpNickName && (tmpnick->uflags > highest))
00996 process_op_item(tmpnick);
00997 }
00998 }
00999 }
01000 } else {
01001
01002 RegNickList *reg2 =
01003 tmp->id.nick ? getRegNickData(tmp->id.nick) : NULL;
01004
01005 if (reg2 && isIdentified(tmp, reg2)
01006 && (tmpnick = getChanOpData(chan, reg2->nick))
01007 && (tmpNickName = ((tmpnick->nickId).getNick())))
01008 process_op_item(tmpnick);
01009 if (isRecognized(tmp, tmp->reg)
01010 && (tmpnick = getChanOpData(chan, nick))
01011 && (tmpNickName = ((tmpnick->nickId).getNick())))
01012 {
01013 process_op_item(tmpnick);
01014 } else {
01015 for (tmpnick = chan->firstOp; tmpnick; tmpnick = tmpnick->next) {
01016 if (!(tmpNickName = (tmpnick->nickId).getNick()))
01017 continue;
01018 if (checkAccess
01019 (tmp->user, tmp->host,
01020 getRegNickData(tmpNickName)) == 1)
01021 process_op_item(tmpnick);
01022 }
01023 }
01024 }
01025
01026
01027
01028 if (!highest) {
01029 cAkickList *tmpak;
01030 char hostmask[HOSTLEN + USERLEN + NICKLEN];
01031 char hostmask2[HOSTLEN + USERLEN + NICKLEN];
01032
01033 snprintf(hostmask, HOSTLEN + USERLEN + NICKLEN, "%s!%s@%s",
01034 tmp->nick, tmp->user, tmp->host);
01035 snprintf(hostmask2, HOSTLEN + USERLEN + NICKLEN, "%s!%s@%s",
01036 tmp->nick, tmp->user, genHostMask(tmp->host));
01037
01038 for (tmpak = chan->firstAkick; tmpak; tmpak = tmpak->next) {
01039 if (!match(tmpak->mask, hostmask)
01040 || !match(tmpak->mask, hostmask2)) {
01041 highest = -1;
01042 break;
01043 }
01044 }
01045 }
01046
01047
01048
01049
01050 if ((chan->flags & CFORCEXFER) && !opFlagged(tmp, OVERRIDE))
01051 return 0;
01052
01053 return highest;
01054 #undef process_op_item
01055 }
01056
01065 int getChanOp(RegChanList * chan, char *nick)
01066 {
01067
01068 if (!chan || !nick)
01069 return 0;
01070
01071 return getMiscChanOp(chan, nick, (chan->flags & CIDENT) == CIDENT,
01072 NULL);
01073 }
01074
01085 int getChanOpId(RegChanList * chan, char *nick)
01086 {
01087
01088 if (!chan || !nick)
01089 return 0;
01090 return getMiscChanOp(chan, nick, 1, NULL);
01091 }
01092
01105 cAccessList *getChanOpData(const RegChanList * chan, const char *nick)
01106 {
01107 RegNickList *rNickPtr;
01108 HashKeyVal hashEnt;
01109
01110 if (nick == NULL || chan == NULL)
01111 return NULL;
01112
01113 rNickPtr = getRegNickData(nick);
01114
01115 if (rNickPtr == NULL)
01116 return NULL;
01117
01118 hashEnt = rNickPtr->regnum.getHashKey() % OPHASHSIZE;
01119
01120 if (chan->op[hashEnt].item == NULL)
01121 return NULL;
01122 else {
01123 cAccessList *tmpnick;
01124
01125 for (tmpnick = chan->op[hashEnt].item; tmpnick;
01126 tmpnick = tmpnick->hashnext) {
01127 if (tmpnick->nickId == rNickPtr->regnum)
01128 return tmpnick;
01129 }
01130 return NULL;
01131 }
01132 }
01133
01141 cBanList *getChanBan(ChanList * chan, char *ban)
01142 {
01143 cBanList *tmp;
01144
01145 if (chan == NULL || ban == NULL)
01146 return NULL;
01147
01148 for (tmp = chan->firstBan; tmp; tmp = tmp->next) {
01149 if (!strcasecmp(ban, tmp->ban))
01150 return tmp;
01151 }
01152
01153 return NULL;
01154 }
01155
01163 cAkickList *getChanAkick(RegChanList * chan, char *akick)
01164 {
01165 cAkickList *tmp;
01166
01167 if (chan == NULL || akick == NULL)
01168 return NULL;
01169
01170 for (tmp = chan->firstAkick; tmp; tmp = tmp->next) {
01171 if (!strcasecmp(akick, tmp->mask))
01172 return tmp;
01173 }
01174
01175 return NULL;
01176 }
01177
01185 void indexAkickItems(RegChanList * chan)
01186 {
01187 cAkickList *tmp;
01188 int i = 1;
01189 for (tmp = chan->firstAkick; tmp; tmp = tmp->next) {
01190 tmp->index = i;
01191 i++;
01192 }
01193 }
01194
01202 void indexOpItems(RegChanList * chan)
01203 {
01204 cAccessList *tmp;
01205 int i = 1;
01206 for (tmp = chan->firstOp; tmp; tmp = tmp->next) {
01207 tmp->index = i;
01208 i++;
01209 }
01210 }
01211
01218 void clearChanIdent(RegChanList * chan)
01219 {
01220 if (!chan)
01221 return;
01222 if (chan->id.nick)
01223 FREE(chan->id.nick);
01224 chan->id.nick = NULL;
01225 chan->id.idnum = RegId(0, 0);
01226 chan->id.timestamp = 0;
01227 }
01228
01238 int isFounder(RegChanList * chan, UserList * nick)
01239 {
01240 UserList *tmp;
01241
01242 if ((chan->flags & CFORCEXFER) && !opFlagged(nick, OVERRIDE))
01243 return 0;
01244
01245 if (chan->id.nick && (tmp = getNickData(chan->id.nick))) {
01246 if (tmp->timestamp < chan->id.timestamp
01247 && tmp->idnum == chan->id.idnum
01248 && !strcasecmp(nick->nick, chan->id.nick)) return 1;
01249 else if (!strcasecmp(nick->nick, chan->id.nick))
01250 clearChanIdent(chan);
01251 } else if (chan->id.nick)
01252 clearChanIdent(chan);
01253
01254 if (nick->reg && (chan->founderId == nick->reg->regnum)
01255 && isRecognized(nick, nick->reg) && chan->facc)
01256 return 1;
01257 else
01258 return 0;
01259 }
01260
01266 int is_sn_chan(char *ch_name)
01267 {
01268 if (!ch_name || !*ch_name)
01269 return 0;
01270
01272 if (!strcasecmp(ch_name, PLUSLCHAN) || !strcasecmp(ch_name, LOGCHAN))
01273 return 1;
01274 return 0;
01275 }
01276
01284 void initRegChanData(RegChanList * chan)
01285 {
01286 long i;
01287
01288 chan->memolevel = 3;
01289 for (i = 0; i < OPHASHSIZE; i++) {
01290 chan->op[i].item = NULL;
01291 chan->op[i].lastitem = NULL;
01292 }
01293 chan->url = NULL;
01294 }
01295
01307 void sendToChanOps(ChanList * chan, char *format, ...)
01308 {
01309 char buffer[IRCBUF];
01310 va_list stuff;
01311
01312 if (!chan || (chan->reg && chan->reg->flags & CQUIET))
01313 return;
01314
01315 va_start(stuff, format);
01316 vsnprintf(buffer, sizeof(buffer), format, stuff);
01317 va_end(stuff);
01318
01319 sSend(":%s NOTICE @%s :(Ops:%s) %s", ChanServ, chan->name, chan->name,
01320 buffer);
01321 }
01322
01323
01335 void sendToChanOpsAlways(ChanList * chan, char *format, ...)
01336 {
01337 char buffer[IRCBUF];
01338 va_list stuff;
01339
01340 va_start(stuff, format);
01341 vsnprintf(buffer, sizeof(buffer), format, stuff);
01342 va_end(stuff);
01343
01344 sSend(":%s NOTICE @%s :(Ops:%s) %s", ChanServ, chan->name, chan->name,
01345 buffer);
01346 }
01347
01371 void banKick(ChanList * chan, UserList * nick, char *format, ...)
01372 {
01373 char user[USERLEN], host[HOSTLEN], theirmask[USERLEN + HOSTLEN + 3];
01374 char buffer[256];
01375 va_list stuff;
01376 cBanList *tmpban;
01377 cNickList *channick;
01378
01379 strncpyzt(user, nick->user, USERLEN);
01380 strncpyzt(host, nick->host, HOSTLEN);
01381
01382 mask(user, host, 1, theirmask);
01383
01384 sSend(":%s MODE %s +b %s", ChanServ, chan->name, theirmask);
01385 tmpban = (cBanList *) oalloc(sizeof(cBanList));
01386 strncpyzt(tmpban->ban, theirmask, sizeof(tmpban->ban));
01387 addChanBan(chan, tmpban);
01388 #ifdef CDEBUG
01389 sSend(":%s PRIVMSG " DEBUGCHAN " :Added ban %s on %s", ChanServ,
01390 theirmask, chan->name);
01391 #endif
01392 va_start(stuff, format);
01393 vsnprintf(buffer, sizeof(buffer), format, stuff);
01394 va_end(stuff);
01395
01396 channick = getChanUserData(chan, nick);
01397
01398 sSend(":%s KICK %s %s :%s", ChanServ, chan->name, nick->nick, buffer);
01399 delChanUser(chan, channick, 1);
01400 }
01401
01411 char *initModeStr(ChanList * chan)
01412 {
01413 char mode[IRCBUF];
01414 char parastr[IRCBUF] = "";
01415 static char mstr[IRCBUF];
01416 int l;
01417
01418
01419 mstr[0] = '\0';
01420 if (!chan || !chan->reg)
01421 return mstr;
01422 *parastr = '\0';
01423
01424 makeModeLockStr(chan->reg, mode);
01425 if (mode[0] != 0) {
01426 if ((chan->reg->mlock & PM_L)) {
01427 l = strlen(parastr);
01428 snprintf(parastr + l, IRCBUF - l, " %ld", chan->reg->limit);
01429 }
01430
01431 if (((chan->reg->mlock & PM_K) || (chan->reg->mlock & MM_K)) &&
01432 ((l = strlen(parastr)) < IRCBUF))
01433 {
01434 snprintf(parastr + l, IRCBUF - l, " %s", chan->reg->key
01435 && *chan->reg->key ? chan->reg->key : "*");
01436 }
01437 }
01438 if (*parastr)
01439 snprintf(mstr, IRCBUF, "%s%s", mode, parastr);
01440 else
01441 snprintf(mstr, IRCBUF, "%s", mode);
01442 return mstr;
01443 }
01444
01453 void createGhostChannel(char *chan)
01454 {
01455 RegChanList *channel;
01456
01457 if ((channel = getRegChanData(chan)))
01458 channel->flags |= CCSJOIN;
01459
01460 sSend(":%s JOIN %s", ChanServ, chan);
01461 sSend(":%s MODE %s +i 1", ChanServ, chan);
01462 }
01463
01473 void deleteGhostChannel(char *chan)
01474 {
01475 RegChanList *channel;
01476
01477 if ((channel = getRegChanData(chan)))
01478 channel->flags &= ~CCSJOIN;
01479
01480 sSend(":%s PART %s :Ahhh, all finished here!", ChanServ, chan);
01481 }
01482
01488 void deleteTimedGhostChannel(char *chan)
01489 {
01490 deleteGhostChannel(chan);
01491 FREE(chan);
01492 }
01493
01494
01512 void makeModeLockStr(RegChanList * chan, char *modelock)
01513 {
01514 char *p = modelock;
01515 bzero(modelock, 20);
01516
01517 *p++ = '+';
01518 if (chan->mlock & PM_I)
01519 *p++ = 'i';
01520 if (chan->mlock & PM_L)
01521 *p++ = 'l';
01522 if (chan->mlock & PM_K)
01523 *p++ = 'k';
01524 if (chan->mlock & PM_M)
01525 *p++ = 'm';
01526 if (chan->mlock & PM_N)
01527 *p++ = 'n';
01528 if (chan->mlock & PM_P)
01529 *p++ = 'p';
01530 if (chan->mlock & PM_S)
01531 *p++ = 's';
01532 if (chan->mlock & PM_T)
01533 *p++ = 't';
01534 if (chan->mlock & PM_H)
01535 *p++ = 'H';
01536 if (chan->mlock & PM_C)
01537 *p++ = 'c';
01538
01539 if (*(p - 1) == '+')
01540 p = modelock;
01541
01542 if (chan->mlock >= 257) {
01543 *p++ = '-';
01544
01545 if (chan->mlock & MM_I)
01546 *p++ = 'i';
01547 if (chan->mlock & MM_L)
01548 *p++ = 'l';
01549 if (chan->mlock & MM_K)
01550 *p++ = 'k';
01551 if (chan->mlock & MM_M)
01552 *p++ = 'm';
01553 if (chan->mlock & MM_N)
01554 *p++ = 'n';
01555 if (chan->mlock & MM_P)
01556 *p++ = 'p';
01557 if (chan->mlock & MM_S)
01558 *p++ = 's';
01559 if (chan->mlock & MM_T)
01560 *p++ = 't';
01561 if (chan->mlock & MM_H)
01562 *p++ = 'H';
01563 if (chan->mlock & MM_C)
01564 *p++ = 'c';
01565 }
01566
01567 if (p == modelock)
01568 strcpy(modelock, "(none)");
01569 else
01570 *p++ = 0;
01571 }
01572
01584 void addUserToChan(UserList * nick, char *channel)
01585 {
01586 char chan[CHANLEN], *badTemp = NULL;
01587 int a = 0;
01588 ChanList *tmp;
01589 cNickList *person;
01590
01591 dlogEntry("addUserToChan(%s, %s)", nick, channel);
01592
01593 if (nick == NULL || channel == NULL || channel[0] == '\0')
01594 return;
01595
01596 if (*channel == ':')
01597 channel++;
01598
01599 while (*channel) {
01600 bzero(chan, CHANLEN);
01601 a = 0;
01602 badTemp = NULL;
01603
01604 while (*channel != ',' && *channel != 0) {
01605 if (a < (CHANLEN - 1))
01606 chan[a] = *channel;
01607 else if (!badTemp)
01608 badTemp = channel;
01609 a++;
01610 channel++;
01611 }
01612
01613 if (badTemp && a >= CHANLEN) {
01614 chan[CHANLEN - 1] = '\0';
01615 sSend(":%s GLOBOPS :%s Joining channel > CHANLEN (%s%s)", ChanServ, nick->nick, chan, badTemp ? badTemp : "");
01616 continue;
01617 }
01618
01619 chan[a] = 0;
01620
01621 if (*channel)
01622 channel++;
01623
01624 if (chan[0] == '0')
01625 remFromAllChans(nick);
01626
01627 else if (chan[0] != '+') {
01628
01629 tmp = getChanData(chan);
01630 if (tmp == NULL)
01631 tmp = (ChanList *) oalloc(sizeof(ChanList));
01632
01633 if (tmp->firstUser == NULL) {
01634 strncpyzt(tmp->name, chan, CHANLEN);
01635 person = (cNickList *) oalloc(sizeof(cNickList));
01636 person->person = nick;
01637 person->op = 0;
01638
01639 addChan(tmp);
01640 addChanUser(tmp, person);
01641
01643 for (a = 0; a < NICKCHANHASHSIZE; a++) {
01644 if (!nick->chan[a]) {
01645 nick->chan[a] = tmp;
01646 break;
01647 }
01648 }
01649 #ifdef CDEBUG
01650 sSend(":%s PRIVMSG " DEBUGCHAN
01651 " :Created channel %s, added %s to it", ChanServ,
01652 chan, nick->nick);
01653 #endif
01654 tmp->reg = getRegChanData(chan);
01655
01656 if (tmp->reg) {
01657 char mode[20];
01658 char themask[NICKLEN + USERLEN + HOSTLEN + 3];
01659
01660 a = getChanOp(tmp->reg, nick->nick);
01661
01662 if (a == -1) {
01663 cAkickList *blah;
01664 char userhost[NICKLEN + USERLEN + HOSTLEN + 3];
01665 char userhostM[NICKLEN + USERLEN + HOSTLEN + 3];
01666
01667 snprintf(userhost, sizeof(userhost),
01668 "%s!%s@%s", nick->nick, nick->user,
01669 nick->host);
01670 snprintf(userhostM, sizeof(userhostM),
01671 "%s!%s@%s", nick->nick, nick->user,
01672 genHostMask(nick->host));
01673
01674 for (blah = tmp->reg->firstAkick; blah;
01675 blah = blah->next) {
01676 strncpyzt(themask, blah->mask,
01677 sizeof(themask));
01678 if (!match(blah->mask, userhost)
01679 || !match(blah->mask, userhostM)) {
01680 cBanList *newban =
01681 (cBanList *) oalloc(sizeof(cBanList));
01682
01683 sSend(":%s MODE %s +b %s", ChanServ,
01684 tmp->reg->name, themask);
01685 strncpyzt(newban->ban, themask, sizeof(newban->ban));
01686 addChanBan(tmp, newban);
01687 break;
01688 }
01689 }
01690
01691 createGhostChannel(tmp->name);
01692 timer(10, deleteTimedGhostChannel,
01693 strdup(tmp->name));
01694 sSend
01695 (":%s KICK %s %s :You have been permanently banned from this channel.",
01696 ChanServ, tmp->reg->name, nick->nick);
01697 delChanUser(tmp, person, 1);
01698 return;
01699 }
01700
01701 if ((tmp->reg->flags & (CBANISH | CCLOSE))
01702 && !isOper(nick)) {
01703 sSend(":%s MODE %s +isnt-o %s", ChanServ,
01704 tmp->name, nick->nick);
01705 createGhostChannel(tmp->name);
01706 timer(30, deleteTimedGhostChannel,
01707 strdup(tmp->name));
01708 banKick(tmp, nick,
01709 "this channel is closed/banished");
01710 return;
01711 }
01712 if (a < tmp->reg->restrictlevel && (a < MFOUNDER)) {
01713 createGhostChannel(tmp->name);
01714 timer(30, deleteTimedGhostChannel,
01715 strdup(tmp->name));
01716 banKick(tmp, nick,
01717 "this channel is restricted to level %i and above",
01718 tmp->reg->restrictlevel);
01719 return;
01720 }
01721 if (!a) {
01722 if (tmp->reg->mlock & PM_I) {
01723 createGhostChannel(tmp->name);
01724 timer(30, deleteTimedGhostChannel,
01725 strdup(tmp->name));
01726 banKick(tmp, nick,
01727 "you must be invited to join this channel.");
01728 return;
01729 }
01730 if ((tmp->reg->mlock & PM_K)
01731 && !(tmp->reg->flags & CCSJOIN)) {
01732 char *p;
01733 createGhostChannel(tmp->name);
01734 timer(30, deleteTimedGhostChannel,
01735 strdup(tmp->name));
01736 sSend(":%s MODE %s +i-o %s", ChanServ,
01737 tmp->name, nick->nick);
01738 sSend(":%s KICK %s %s :%s", ChanServ,
01739 tmp->name, nick->nick,
01740 "this is a keyed channel.");
01741 sSend(":%s MODE %s -i", ChanServ, tmp->name);
01742 if ((p = initModeStr(tmp))) {
01743 sSend(":%s MODE %s %s", ChanServ,
01744 tmp->name, p);
01745 #ifdef IRCD_MLOCK
01746 sSend(":%s MLOCK %s %s", ChanServ,
01747 tmp->name, p);
01748 #endif
01749 }
01750 remUserFromChan(nick, tmp->name);
01751 return;
01752 }
01753 }
01754 if ((a < AOP) && (a >= MAOP)) {
01755 sSend(":%s MODE %s +v %s", ChanServ, tmp->name,
01756 nick->nick);
01757 person->op |= CHANVOICE;
01758 tmp->reg->timestamp = CTime;
01759 if (tmp && tmp->name
01760 && !strcasecmp(tmp->name, HELPOPS_CHAN)
01761 && (getChanOp(tmp->reg, nick->nick) >= 4)) {
01762 sSend(":ChanServ MODE %s :+h", nick->nick);
01763 nick->oflags |= NISHELPOP;
01764 }
01765 } else if (a && a >= AOP) {
01766 sSend(":%s MODE %s +o %s", ChanServ, tmp->name,
01767 nick->nick);
01768 person->op |= CHANOP;
01769 tmp->reg->timestamp = CTime;
01770 if (tmp && tmp->name
01771 && !strcasecmp(tmp->name, HELPOPS_CHAN)) {
01772 sSend(":ChanServ MODE %s :+h", nick->nick);
01773 nick->oflags |= NISHELPOP;
01774 }
01775 }
01776 if (tmp->reg->flags & CKTOPIC)
01777 if (tmp->reg->topic)
01778 sSend(":%s TOPIC %s %s %lu :%s", ChanServ,
01779 tmp->name, tmp->reg->tsetby,
01780 tmp->reg->ttimestamp, tmp->reg->topic);
01781 if (tmp->reg->autogreet)
01782 sSend(":%s NOTICE %s :[%s] %s", ChanServ,
01783 nick->nick, tmp->name, tmp->reg->autogreet);
01784
01785 makeModeLockStr(tmp->reg, mode);
01786
01787 if (mode[0] != 0) {
01788 char parastr[IRCBUF * 2];
01789
01790 *parastr = '\0';
01791 if ((tmp->reg->mlock & PM_L))
01792 sprintf(parastr + strlen(parastr), " %ld",
01793 tmp->reg->limit);
01794 if ((tmp->reg->mlock & PM_K)
01795 || (tmp->reg->mlock & MM_K)) sprintf(parastr +
01796 strlen
01797 (parastr),
01798 " %s",
01799 tmp->reg->
01800 key
01801 && *tmp->
01802 reg->
01803 key ?
01804 tmp->reg->
01805 key :
01806 "*");
01807 sSend(":%s MODE %s %s%s", ChanServ, tmp->name,
01808 mode, parastr);
01809 #ifdef IRCD_MLOCK
01810 sSend(":%s MLOCK %s %s%s", ChanServ, tmp->name,
01811 mode, parastr);
01812 #endif
01813 }
01814 }
01815 } else {
01816 person = (cNickList *) oalloc(sizeof(cNickList));
01817 person->person = nick;
01818 person->op = 0;
01819 addChanUser(tmp, person);
01820
01821 for (a = 0; a < NICKCHANHASHSIZE; a++) {
01822 if (!nick->chan[a]) {
01823 nick->chan[a] = tmp;
01824 break;
01825 }
01826 }
01827 if (tmp->reg) {
01828 char themask[NICKLEN + USERLEN + HOSTLEN + 3];
01829
01830 a = getChanOp(tmp->reg, nick->nick);
01831 if (a == -1) {
01832 cAkickList *blah;
01833 char userhost[NICKLEN + USERLEN + HOSTLEN + 3];
01834 char userhostM[NICKLEN + USERLEN + HOSTLEN + 3];
01835
01836 snprintf(userhost, sizeof(userhost),
01837 "%s!%s@%s", nick->nick, nick->user,
01838 nick->host);
01839 snprintf(userhostM, sizeof(userhostM),
01840 "%s!%s@%s", nick->nick, nick->user,
01841 genHostMask(nick->host));
01842
01843 for (blah = tmp->reg->firstAkick; blah;
01844 blah = blah->next) {
01845 strncpyzt(themask, blah->mask,
01846 sizeof(themask));
01847 if (!match(blah->mask, userhost)
01848 || !match(blah->mask, userhostM)) {
01849 cBanList *newban =
01850 (cBanList *) oalloc(sizeof(cBanList));
01851 sSend(":%s MODE %s +b %s", ChanServ, chan,
01852 themask);
01853 strncpyzt(newban->ban, themask, sizeof(newban->ban));
01854 addChanBan(tmp, newban);
01855 break;
01856 }
01857 }
01858 sSend
01859 (":%s KICK %s %s :You have been permanently banned from this channel.",
01860 ChanServ, chan, nick->nick);
01861 delChanUser(tmp, person, 1);
01862 return;
01863 }
01864 if ((tmp->reg->flags & (CBANISH | CCLOSE))
01865 && !isOper(nick)) {
01866 banKick(tmp, nick,
01867 "this channel is closed/banished");
01868 return;
01869 }
01870 if (a < tmp->reg->restrictlevel) {
01871 banKick(tmp, nick,
01872 "this channel is restricted to level %i+",
01873 tmp->reg->restrictlevel);
01874 return;
01875 }
01876 if ((a >= MAOP) && (a < AOP)) {
01877 sSend(":%s MODE %s +v %s", ChanServ, tmp->name,
01878 nick->nick);
01879 person->op |= CHANVOICE;
01880 tmp->reg->timestamp = CTime;
01881 if (tmp && tmp->name && tmp->reg
01882 && !strcasecmp(tmp->name, HELPOPS_CHAN)
01883 && (getChanOp(tmp->reg, nick->nick) >= 4)) {
01884 sSend(":ChanServ MODE %s :+h", nick->nick);
01885 nick->oflags |= NISHELPOP;
01886 }
01887 } else if (a && a >= AOP) {
01888 sSend(":%s MODE %s +o %s", ChanServ, tmp->name,
01889 nick->nick);
01890 person->op |= CHANOP;
01891 tmp->reg->timestamp = CTime;
01892 if (tmp && tmp->name
01893 && !strcasecmp(tmp->name, HELPOPS_CHAN)) {
01894 sSend(":ChanServ MODE %s :+h", nick->nick);
01895 nick->oflags |= NISHELPOP;
01896 }
01897 }
01898 if (tmp->reg->autogreet)
01899 sSend(":%s NOTICE %s :[%s] %s", ChanServ,
01900 nick->nick, tmp->name, tmp->reg->autogreet);
01901 }
01902 #ifdef CDEBUG
01903 sSend(":%s PRIVMSG " DEBUGCHAN " :Added %s to channel %s",
01904 ChanServ, nick->nick, chan);
01905 #endif
01906 }
01907 }
01908 }
01909 }
01910
01918 void remUserFromChan(UserList * nick, char *channel)
01919 {
01920 char chan[CHANLEN], *badTemp = NULL;
01921 int a;
01922 ChanList *tmp;
01923 cNickList *person;
01924
01925 if (*channel == ':')
01926 channel++;
01927
01928 while (*channel) {
01929 bzero(chan, CHANLEN);
01930 badTemp = NULL;
01931 a = 0;
01932
01933 while (*channel != ',' && *channel != 0) {
01934 if (a < (CHANLEN - 1))
01935 chan[a] = *channel;
01936 else if (!badTemp)
01937 badTemp = channel;
01938 a++;
01939 channel++;
01940 }
01941 chan[a] = 0;
01942 a = 0;
01943
01944 if (badTemp) {
01945 continue;
01946 }
01947
01948 if (*channel)
01949 channel++;
01950
01951 if (chan[0] != '+') {
01952 tmp = getChanData(chan);
01953
01954 if (tmp != NULL) {
01955 person = getChanUserData(tmp, nick);
01956 if (person == NULL) {
01957
01958
01959
01960
01961
01962 return;
01963 }
01964
01965 if (tmp && (nick->oflags & NISHELPOP)
01966 && !(nick->oflags & NISOPER) && tmp->name
01967 && !strcasecmp(tmp->name, HELPOPS_CHAN)
01968 && tmp->reg && (getChanOp(tmp->reg, nick->nick) <= 5)) {
01969 sSend(":ChanServ MODE %s :-h", nick->nick);
01970 nick->oflags &= ~NISHELPOP;
01971 }
01972
01973 for (a = 0; a < NICKCHANHASHSIZE; a++) {
01974 if (nick->chan[a] == tmp) {
01975 nick->chan[a] = NULL;
01976 break;
01977 }
01978 }
01979 delChanUser(tmp, person, 1);
01980 tmp = NULL;
01981 #ifdef CDEBUG
01982 sSend(":%s PRIVMSG " DEBUGCHAN " :Removed %s from %s",
01983 ChanServ, nick->nick, chan);
01984 #endif
01985
01986 }
01987 }
01988 }
01989 }
01990
01996 void remFromAllChans(UserList * nick)
01997 {
01998 int i, a;
01999
02000 #ifdef CDEBUG
02001 sSend(":%s PRIVMSG " DEBUGCHAN " :Clearing %s from ALL channels",
02002 ChanServ, nick->nick);
02003 #endif
02004 if (nick == NULL)
02005 return;
02006
02007 for (i = 0; i < NICKCHANHASHSIZE; i++) {
02008 if (nick->chan[i]) {
02009 cNickList *ctmp = getChanUserData(nick->chan[i], nick);
02010
02011 if (ctmp)
02012 delChanUser(nick->chan[i], ctmp, 1);
02013 nick->chan[i] = NULL;
02014
02015
02016 for (a = i; a < NICKCHANHASHSIZE; a++)
02017 if (nick->chan[i] && nick->chan[a] == nick->chan[i])
02018 nick->chan[a] = NULL;
02019 }
02020 }
02021 }
02022
02029 void changeNickOnAllChans(UserList * oldnick, UserList * newnick)
02030 {
02031 int i;
02032 cNickList *tmpnick, *addnick;
02033
02034 #ifdef CDEBUG
02035 sSend(":%s PRIVMSG " DEBUGCHAN " :Changing nick for %s->%s", ChanServ,
02036 oldnick->nick, newnick->nick);
02037 #endif
02038
02039 for (i = 0; i < NICKCHANHASHSIZE; i++) {
02040 if (oldnick->chan[i]) {
02041 addnick = (cNickList *) oalloc(sizeof(cNickList));
02042 tmpnick = getChanUserData(oldnick->chan[i], oldnick);
02043 if (!tmpnick)
02044 FREE(addnick);
02045 else {
02046 addnick->op = tmpnick->op;
02047 addnick->person = newnick;
02048 newnick->chan[i] = oldnick->chan[i];
02049 addChanUser(newnick->chan[i], addnick);
02050 delChanUser(oldnick->chan[i], tmpnick, 1);
02051 }
02052 } else
02053 newnick->chan[i] = NULL;
02054 }
02055 }
02056
02057
02065 void setChanMode(char **args, int numargs)
02066 {
02067 int on = 1, onarg = 4, i = 0;
02068 ChanList *tmp = getChanData(args[2]);
02069 cBanList *tmpban;
02070 cNickList *tmpnick;
02071 char mode[20];
02072
02073 if (tmp == NULL)
02074 return;
02075
02076 if (numargs < 3)
02077 return;
02078
02079 for (i = 0; args[3][i]; i++) {
02080 switch (args[3][i]) {
02081 case '+':
02082 on = 1;
02083 break;
02084 case '-':
02085 on = 0;
02086 break;
02087
02088 case 'b':
02089 if (on) {
02090 tmpban = (cBanList *) oalloc(sizeof(cBanList));
02091 strncpyzt(tmpban->ban, args[onarg], sizeof(tmpban->ban));
02092 addChanBan(tmp, tmpban);
02093 #ifdef CDEBUG
02094 sSend(":%s PRIVMSG " DEBUGCHAN " :Added ban %s on %s",
02095 ChanServ, args[onarg], tmp->name);
02096 #endif
02097 } else {
02098 tmpban = getChanBan(tmp, args[onarg]);
02099 if (tmpban) {
02100 #ifdef CDEBUG
02101 sSend(":%s PRIVMSG " DEBUGCHAN
02102 " :Removed ban %s on %s", ChanServ, args[onarg],
02103 tmp->name);
02104 #endif
02105 delChanBan(tmp, tmpban);
02106 }
02107 }
02108 onarg++;
02109 break;
02110
02111 case 'i':
02112 if (on) {
02113 tmp->modes |= PM_I;
02114 #ifdef CDEBUG
02115 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s +i", ChanServ,
02116 tmp->name);
02117 #endif
02118 } else {
02119 tmp->modes &= ~(PM_I);
02120 #ifdef CDEBUG
02121 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s -i", ChanServ,
02122 tmp->name);
02123 #endif
02124 }
02125 break;
02126 case 'l':
02127 if (on) {
02128 tmp->modes |= PM_L;
02129 #ifdef CDEBUG
02130 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s +l %lu", ChanServ,
02131 tmp->name, tmp->reg->limit);
02132 #endif
02133 } else {
02134 tmp->modes &= ~(PM_L);
02135 #ifdef CDEBUG
02136 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s -l", ChanServ,
02137 tmp->name);
02138 #endif
02139 }
02140 break;
02141 case 'k':
02142 if (on) {
02143 tmp->modes |= PM_K;
02144 #ifdef CDEBUG
02145 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s +k %s", ChanServ,
02146 tmp->name, tmp->reg->key);
02147 #endif
02148 } else {
02149 tmp->modes &= ~(PM_K);
02150 #ifdef CDEBUG
02151 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s -k %s", ChanServ,
02152 tmp->reg->name, args[onarg]);
02153 #endif
02154 }
02155 onarg++;
02156 break;
02157 case 'm':
02158 if (on) {
02159 tmp->modes |= PM_M;
02160 #ifdef CDEBUG
02161 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s +m", ChanServ,
02162 tmp->name);
02163 #endif
02164 } else {
02165 tmp->modes &= ~(PM_M);
02166 #ifdef CDEBUG
02167 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s -m", ChanServ,
02168 tmp->name);
02169 #endif
02170 }
02171 break;
02172 case 'n':
02173 if (on) {
02174 tmp->modes |= PM_N;
02175 #ifdef CDEBUG
02176 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s +n", ChanServ,
02177 tmp->name);
02178 #endif
02179 } else {
02180 tmp->modes &= ~(PM_N);
02181 #ifdef CDEBUG
02182 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s -m", ChanServ,
02183 tmp->name);
02184 #endif
02185 }
02186 break;
02187 case 'o':
02188 if (on) {
02189 tmpnick = getChanUserData(tmp, getNickData(args[onarg]));
02190 if (!tmpnick) {
02191 }
02192
02193 else if (tmp->reg) {
02194 if (getChanOp(tmp->reg, args[onarg]) < 5
02195 && !(tmp->reg->flags & CFORCEXFER)
02196 && (tmp->reg->flags & COPGUARD
02197 || tmp->firstUser == tmp->lastUser)) {
02198 sSend
02199 (":%s NOTICE %s :You are not allowed ops in %s",
02200 ChanServ, args[onarg], tmp->name);
02201 sSend(":%s MODE %s -o %s", ChanServ, tmp->name,
02202 args[onarg]);
02203 } else {
02204 tmpnick->op |= CHANOP;
02205 #ifdef CDEBUG
02206 sSend(":%s PRIVMSG " DEBUGCHAN " :Oped %s in %s",
02207 ChanServ, args[onarg], tmp->name);
02208 #endif
02209 }
02210 } else {
02211 tmpnick->op |= CHANOP;
02212 #ifdef CDEBUG
02213 sSend(":%s PRIVMSG " DEBUGCHAN " :Oped %s in %s",
02214 ChanServ, args[onarg], tmp->name);
02215 #endif
02216 }
02217 } else {
02218 tmpnick = getChanUserData(tmp, getNickData(args[onarg]));
02219 if (tmpnick) {
02220 if (tmp->reg) {
02221 int t_lev = getChanOp(tmp->reg, args[onarg]);
02222 int s_lev = getChanOp(tmp->reg, (args[0] ));
02223
02224 if ((t_lev > s_lev) && (t_lev >= AOP)
02225 && tmp->reg->flags & CPROTOP)
02226 sSend(":%s MODE %s +o %s", ChanServ, tmp->name,
02227 args[onarg]);
02228 else
02229 tmpnick->op &= ~CHANOP;
02230 } else
02231 tmpnick->op &= ~CHANOP;
02232 #ifdef CDEBUG
02233 sSend(":%s PRIVMSG " DEBUGCHAN " :DeOped %s in %s",
02234 ChanServ, args[onarg], tmp->name);
02235 #endif
02236 }
02237 }
02238 onarg++;
02239 break;
02240 case 'p':
02241 if (on) {
02242 tmp->modes |= PM_P;
02243 #ifdef CDEBUG
02244 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s +p", ChanServ,
02245 tmp->name);
02246 #endif
02247 } else {
02248 tmp->modes &= ~(PM_P);
02249 #ifdef CDEBUG
02250 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s -p", ChanServ,
02251 tmp->name);
02252 #endif
02253 }
02254 break;
02255 case 's':
02256 if (on) {
02257 tmp->modes |= PM_S;
02258 #ifdef CDEBUG
02259 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s +s", ChanServ,
02260 tmp->name);
02261 #endif
02262 } else {
02263 tmp->modes &= ~(PM_S);
02264 #ifdef CDEBUG
02265 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s -s", ChanServ,
02266 tmp->name);
02267 #endif
02268 }
02269 break;
02270 case 't':
02271 if (on) {
02272 tmp->modes |= PM_T;
02273 #ifdef CDEBUG
02274 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s +t", ChanServ,
02275 tmp->name);
02276 #endif
02277 } else {
02278 tmp->modes &= ~(PM_T);
02279 #ifdef CDEBUG
02280 sSend(":%s PRIVMSG " DEBUGCHAN " :Set %s -t", ChanServ,
02281 tmp->name);
02282 #endif
02283 }
02284 break;
02285
02286 case 'H':
02287 if (on)
02288 tmp->modes |= PM_H;
02289 else
02290 tmp->modes &= ~PM_H;
02291 break;
02292
02293 case 'c':
02294 if (on) tmp->modes |= PM_C;
02295 else tmp->modes &= ~PM_C;
02296 break;
02297
02298 case 'v':
02299 if (on) {
02300 tmpnick = getChanUserData(tmp, getNickData(args[onarg]));
02301 if (tmpnick) {
02302 tmpnick->op |= CHANVOICE;
02303 #ifdef CDEBUG
02304 sSend(":%s PRIVMSG " DEBUGCHAN " :Oped %s in %s",
02305 ChanServ, args[onarg], tmp->name);
02306 #endif
02307 }
02308 } else {
02309 tmpnick = getChanUserData(tmp, getNickData(args[onarg]));
02310 if (tmpnick) {
02311 tmpnick->op &= ~CHANVOICE;
02312 #ifdef CDEBUG
02313 sSend(":%s PRIVMSG " DEBUGCHAN " :DeOped %s in %s",
02314 ChanServ, args[onarg], tmp->name);
02315 #endif
02316 }
02317 }
02318 onarg++;
02319 break;
02320 }
02321
02322 }
02323
02324 if (tmp->reg) {
02325 makeModeLockStr(tmp->reg, mode);
02326 if (mode[0] != 0) {
02327 char parastr[IRCBUF * 2];
02328
02329 *parastr = '\0';
02330 if ((tmp->reg->mlock & PM_L))
02331 sprintf(parastr + strlen(parastr), " %ld",
02332 tmp->reg->limit);
02333 if ((tmp->reg->mlock & PM_K) || (tmp->reg->mlock & MM_K))
02334 sprintf(parastr + strlen(parastr), " %s",
02335 (tmp->reg->key
02336 && *tmp->reg->key ? tmp->reg->key : "*"));
02337 sSend(":%s MODE %s %s%s", ChanServ, tmp->name, mode, parastr);
02338 #ifdef IRCD_MLOCK
02339 sSend(":%s MLOCK %s %s%s", ChanServ, tmp->name, mode, parastr);
02340 #endif
02341 }
02342 }
02343 }
02344
02355 void setChanTopic(char **args, int numargs)
02356 {
02357 RegChanList *tmp;
02358 char tmptopic[IRCBUF + 1];
02359
02360
02361 if (numargs < 3)
02362 return;
02363
02364
02365
02366
02367
02368 tmp = getRegChanData(args[2]);
02369 if (tmp == NULL)
02370 return;
02371
02372
02373
02374
02375
02376 if ((numargs < 4) || getChanOp(tmp, args[3]) < tmp->tlocklevel) {
02377 if (tmp->topic)
02378 sSend(":%s TOPIC %s %s %lu :%s", myname, tmp->name,
02379 tmp->tsetby, tmp->ttimestamp, tmp->topic);
02380 return;
02381 }
02382
02383 if (tmp->topic)
02384 FREE(tmp->topic);
02385 strncpyzt(tmp->tsetby, args[3], NICKLEN);
02386 tmp->ttimestamp = atol(args[4]);
02387
02388
02389
02390
02391
02392
02393 if (*args[5] == ':')
02394 args[5]++;
02395
02396
02397
02398
02399
02400 bzero(tmptopic, TOPIC_MAX);
02401 parse_str(args, numargs, 5, tmptopic, TOPIC_MAX);
02402 tmptopic[TOPIC_MAX] = '\0';
02403
02404 tmp->topic = strdup(tmptopic);
02405 }
02406
02419 const char *opLevelName(int level, int x_case)
02420 {
02421 static char *undef_string[3] = {
02422 "Op", "operator", "Operator"
02423 };
02424
02425 if (x_case > 2 || x_case < 0)
02426 x_case = level = 0;
02427 if (level == -1 || level > FOUNDER)
02428 return undef_string[x_case];
02429 return oplev_table[level].v[x_case];
02430 }
02431
02439 int opNameLevel(const char *name)
02440 {
02441 char *p;
02442 int level = 0, j = 0;
02443
02444 if (!name || !*name || strlen(name) > 15)
02445 return -1;
02446 if (!strcasecmp(name, "off") || !strcasecmp(name, "user"))
02447 return 0;
02448
02449 if (isdigit(*name)) {
02450 level = atoi(name);
02451 if (level >= 0 && level <= FOUNDER)
02452 return level;
02453 }
02454
02455
02456 if (*name && (p = strchr(name, '(')) && *p == '(' && isdigit(p[1])) {
02457 if ((isdigit(p[2]) && p[3] == ')') || p[2] == ')')
02458 return atoi(p + 1);
02459 }
02460
02461 for (level = 0; level <= FOUNDER; level++) {
02462 for (j = 0; j < 3; j++)
02463 if (!strcasecmp(oplev_table[level].v[j], name))
02464 return level;
02465 }
02466 return -1;
02467 }
02468
02472 void syncChanData(time_t next)
02473 {
02474 nextCsync = next;
02475 saveChanData(firstRegChan);
02476 }
02477
02478
02479
02480
02481
02482 int ValidChannelName(const char* nmtoken)
02483 {
02484 const char *p;
02485
02486 if (!nmtoken || !*nmtoken)
02487 return 0;
02488 if ((nmtoken[0] != '#' && nmtoken[0] != '+') || !nmtoken[1])
02489 return 0;
02490 for(p = nmtoken; *p; p++) {
02491 if (!iscntrl(*p) && !isspace(*p) && (unsigned char)*p != 0xA0)
02492 continue;
02493 return 0;
02494 }
02495 return 1;
02496 }
02497
02498
02503 void expireChans(char *arg)
02504 {
02505 time_t timestart;
02506 time_t timeend;
02507 RegChanList *regchan;
02508 RegChanList *next;
02509 ChanList *chan;
02510
02511 char backup[50];
02512 int i;
02513
02514 arg = arg;
02515
02516 i = 0;
02517 mostchans = 0;
02518 timestart = time(NULL);
02519
02520 strftime(backup, 49, "chanserv/backups/chanserv.db%d%m%Y",
02521 localtime(×tart));
02522 rename("chanserv/chanserv.db", backup);
02523 saveChanData(firstRegChan);
02524
02525 for (regchan = firstRegChan; regchan; regchan = next) {
02526 next = regchan->next;
02527 mostchans++;
02528
02529 if ((timestart - regchan->timestamp) >= CHANDROPTIME) {
02530 if ((regchan->flags & (CHOLD | CBANISH)))
02531 continue;
02532 #if 0
02533 printf("Dropping channel %s: %ld %ld %ld\n", regchan->name,
02534 timestart, regchan->timestamp,
02535 timestart - regchan->timestamp);
02536 #endif
02537
02538 chan = getChanData(regchan->name);
02539 if (chan != NULL)
02540 chan->reg = NULL;
02541 chanlog->log(NULL, CSE_EXPIRE, regchan->name);
02542 delRegChan(regchan);
02543 i++;
02544 }
02545 }
02546
02547 timeend = time(NULL);
02548 sSend(":%s GLOBOPS :ChanServ EXPIRE(%d/%lu) %ld seconds", ChanServ, i,
02549 mostchans, (timeend - timestart));
02550 timer((int)(2.5 * 3600), (void (*)(char *))expireChans, NULL);
02551 }
02552
02553
02554
02555
02556
02557
02558
02562 void sendToChanServ(UserList * nick, char **args, int numargs)
02563 {
02564 char *from = nick->nick;
02565 interp::parser * cmd;
02566
02567
02568
02569 char crud[IRCBUF];
02570
02571 if (index(args[0], '#')) {
02572 counterOldCSFmt++;
02573 strncpyzt(crud, args[0], IRCBUF);
02574 strcpy(args[0], args[1]);
02575 strcpy(args[1], crud);
02576 }
02577
02578 cmd =
02579 new interp::parser(ChanServ, getOpFlags(nick), chanserv_commands,
02580 args[0]);
02581 if (!cmd)
02582 return;
02583
02584 if ((cmd->getCmdFlags() & CMD_REG) && !nick->reg) {
02585 sSend
02586 (":%s NOTICE %s :You nick must be registered to use that command.",
02587 ChanServ, from);
02588 return;
02589 }
02590
02591 switch (cmd->run(nick, args, numargs)) {
02592 default:
02593 break;
02594 case RET_FAIL:
02595 sSend(":%s NOTICE %s :Unknown command %s.\r\n"
02596 ":%s NOTICE %s :Please try /msg %s HELP", ChanServ, from,
02597 args[0], ChanServ, from, ChanServ);
02598 break;
02599 case RET_OK_DB:
02600 sSend(":%s NOTICE %s :Next database synch(save) in %ld minutes.",
02601 ChanServ, nick->nick, (long)((nextCsync - CTime) / 60));
02602 break;
02603 }
02604 }
02605
02606
02607
02613 CCMD(cs_help)
02614 {
02615 help(nick->nick, ChanServ, args, numargs);
02616 return RET_OK;
02617 }
02618
02619
02620
02628 CCMD(cs_chanop)
02629 {
02630 const char *from = nick->nick;
02631 const char *cmdName = "op", *cTargNick = NULL;
02632 int targLevel = -1, i;
02633 int is_add = 0, is_del = 0, is_chanop = 0;
02634 char cmd_x[25] = "";
02635 RegChanList *chan;
02636
02637 struct
02638 {
02639 const char *name;
02640 int lev;
02641 } op_alias_table[] = {
02642 { "maop", MAOP }, { "aop", AOP },
02643 { "msop", MSOP}, { "sop", SOP },
02644 { "mfounder", MFOUNDER}, { "founder", FOUNDER },
02645 { NULL }
02646 };
02647
02648 cmd_x[0] = '\0';
02649
02650 if (numargs >= 1 && args[0] && *args[0]) {
02651 for (i = 0; args[0][i] && i < 25; i++)
02652 cmd_x[i] = toupper(args[0][i]);
02653 cmd_x[i] = '\0';
02654 }
02655
02656 if (cmd_x[0] == '-' && strcmp(cmd_x, "-ops"))
02657 strcpy(cmd_x, "chanop");
02658
02659 if (numargs < 3) {
02660 sSend(":%s NOTICE %s :Usage: %s ADD <nick>", ChanServ, from,
02661 cmd_x);
02662 sSend(":%s NOTICE %s : %s DEL <nick | index#>", ChanServ,
02663 from, cmd_x);
02664 sSend(":%s NOTICE %s : %s LIST", ChanServ, from, cmd_x);
02665 sSend
02666 (":%s NOTICE %s :Type `/msg %s HELP %s', for more information.",
02667 ChanServ, from, ChanServ, cmd_x);
02668 return RET_SYNTAX;
02669 }
02670
02671 if (!(chan = getRegChanData(args[1]))) {
02672 sSend(":%s NOTICE %s :%s is not a registered channel.", ChanServ,
02673 from, args[1]);
02674 return RET_NOTARGET;
02675 }
02676
02677 if (!(tolower(args[0][0]) == 'c' && !strcasecmp(args[0] + 1, "hanop"))) {
02678 for (i = 0; op_alias_table[i].name; i++)
02679 if (op_alias_table[i].name[0] == tolower(*args[0])
02680 && !strcasecmp(1 + op_alias_table[i].name, 1 + args[0]))
02681 break;
02682 if (op_alias_table[i].name) {
02683 targLevel = op_alias_table[i].lev;
02684 cmdName = op_alias_table[i].name;
02685 }
02686 } else
02687 is_chanop = 1;
02688
02689 if ((is_add = !strcasecmp(args[2], "add"))
02690 || (is_del = !strncasecmp(args[2], "del", 3))) {
02691 if (numargs < 3) {
02692 sSend(":%s NOTICE %s :%s who?", ChanServ, from,
02693 tolower(*args[2]) == 'd' ? "delete" : "add");
02694 return RET_SYNTAX;
02695 }
02696
02697 cTargNick = args[3];
02698 if (is_add) {
02699 if ((numargs >= 5)) {
02700 int newTargLevel = opNameLevel(args[4]);
02701
02702 if (newTargLevel < 1 || newTargLevel > FOUNDER)
02703 newTargLevel = -1;
02704
02705 if (!is_chanop) {
02706 if ((newTargLevel > targLevel)
02707 || (newTargLevel < MAOP - 1)
02708 || (newTargLevel <= AOP && targLevel == MSOP)
02709 || (newTargLevel < MSOP && targLevel == SOP)
02710 || (newTargLevel <= SOP && targLevel == MFOUNDER)
02711 ) {
02712 sSend
02713 (":%s NOTICE %s :Error: Invalid level for %s command.",
02714 ChanServ, from, cmdName);
02715 sSend
02716 (":%s NOTICE %s :Type `/msg %s HELP %s', for more information.",
02717 ChanServ, from, ChanServ, cmd_x);
02718 return RET_SYNTAX;
02719 }
02720 }
02721 targLevel = newTargLevel;
02722 }
02723 return do_chanop(CS_ADDOP, nick, chan, cTargNick, targLevel);
02724 } else
02725 return do_chanop(CS_DELOP, nick, chan, cTargNick, targLevel);
02726 } else if (!strcasecmp(args[2], "list")) {
02727 if ((numargs >= 4))
02728 cTargNick = args[3];
02729 return do_chanop(CS_LISTOP, nick, chan, cTargNick, targLevel);
02730 } else {
02731 sSend(":%s NOTICE %s :Unknown %s command %s.\r"
02732 ":%s NOTICE %s :/msg %s HELP for assistance", ChanServ, from,
02733 cmdName, args[2], ChanServ, from, ChanServ);
02734 return RET_SYNTAX;
02735 }
02736
02737 return RET_OK;
02738 }
02739
02740
02741
02754 CCMD(cs_akick)
02755 {
02756 const char *from = nick->nick;
02757 char theCmd[256];
02758 int i = 3;
02759
02760 if (numargs < 2) {
02761 sSend(":%s NOTICE %s :Channel name required", ChanServ, from);
02762
02763 return RET_SYNTAX;
02764 }
02765
02766 if (numargs < 3) {
02767 sSend(":%s NOTICE %s :Not enough arguments to command", ChanServ,
02768 from);
02769 return RET_SYNTAX;
02770 }
02771
02772 strncpyzt(theCmd, args[2], sizeof(theCmd));
02773
02774 while (i < numargs) {
02775 strncpyzt(args[i - 1], args[i], ARGLEN);
02776 i++;
02777 }
02778 numargs--;
02779
02780 if (!strcasecmp(theCmd, "add"))
02781 return cs_addak(nick, args, numargs);
02782 else if (!match("del*", theCmd))
02783 return cs_delak(nick, args, numargs);
02784 else if (!strcasecmp(theCmd, "list"))
02785 return cs_listak(nick, args, numargs);
02786 else {
02787 sSend(":%s NOTICE %s :Unknown akick command %s.\r"
02788 ":%s NOTICE %s :/msg %s HELP for assistance", ChanServ, from,
02789 args[2], ChanServ, from, ChanServ);
02790 return RET_SYNTAX;
02791 }
02792 return RET_OK;
02793 }
02794
02795
02796
02806 CCMD(cs_mdeop)
02807 {
02808 char *from = nick->nick;
02809 char accNick[NICKLEN+1];
02810 ChanList *chan;
02811 cNickList *tmp;
02812 int aclvl;
02813
02814 if (numargs < 2) {
02815 sSend(":%s NOTICE %s :You must specify a channel", ChanServ, from);
02816 return RET_SYNTAX;
02817 }
02818
02819 chan = getChanData(args[1]);
02820 if (!chan) {
02821 sSend(":%s NOTICE %s :%s is not currently active", ChanServ, from,
02822 args[1]);
02823 return RET_NOTARGET;
02824 }
02825
02826 chan->reg = getRegChanData(args[1]);
02827 if (!chan->reg) {
02828 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
02829 args[1]);
02830 return RET_NOTARGET;
02831 }
02832
02833 aclvl = getMiscChanOp(chan->reg, from, ChanGetIdent(chan->reg), accNick);
02834 if (opFlagged(nick, OVERRIDE | OSERVOP)
02835 || opFlagged(nick, OVERRIDE | ODMOD)) aclvl = FOUNDER + 1;
02836
02837 if (MAOP > aclvl) {
02838 sSend
02839 (":%s NOTICE %s :You must be at least level %i in the channel op list to MDEOP.",
02840 ChanServ, from, MAOP);
02841 return RET_NOPERM;
02842 }
02843 sendToChanOpsAlways(chan, "%s!%s is using command MDEOP on %s", accNick, from,
02844 chan->name);
02845 for (tmp = chan->firstUser; tmp; tmp = tmp->next) {
02846 if (aclvl > getChanOp(chan->reg, tmp->person->nick)) {
02847 sSend(":%s MODE %s -o %s", ChanServ, chan->name,
02848 tmp->person->nick);
02849 tmp->op = 0;
02850 } else
02851 sSend
02852 (":%s NOTICE %s :Your access is not high enough to deop %s",
02853 ChanServ, from, tmp->person->nick);
02854 }
02855 return RET_OK;
02856 }
02857
02858
02859
02869 CCMD(cs_mkick)
02870 {
02871 char *from = nick->nick;
02872 char accNick[NICKLEN+1];
02873 ChanList *chan;
02874 cNickList *tmp;
02875 cNickList *next;
02876 int aclvl;
02877
02878 if (numargs < 2) {
02879 sSend(":%s NOTICE %s :You must specify a channel", ChanServ, from);
02880 return RET_SYNTAX;
02881 }
02882
02883 chan = getChanData(args[1]);
02884 if (chan == NULL) {
02885 sSend(":%s NOTICE %s :%s is not currently active", ChanServ, from,
02886 args[1]);
02887 return RET_NOTARGET;
02888 }
02889
02890 if (chan->reg == NULL) {
02891 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
02892 args[1]);
02893 return RET_NOTARGET;
02894 }
02895
02896 aclvl = getMiscChanOp(chan->reg, from, 1, accNick);
02897
02898 if ((SOP > aclvl) && (!isOper(nick))) {
02899 sSend
02900 (":%s NOTICE %s :You must be at least level %i in the channel op list to MKICK.",
02901 ChanServ, from, SOP);
02902 return RET_NOPERM;
02903 }
02904
02905 if (isOper(nick) && (SOP > aclvl)) {
02906 if (numargs > 2) {
02907 if (strncmp(args[2], "-o", 2) == 0) {
02908 sSend
02909 (":%s GLOBOPS :%s is using MKICK on %s (without SOP level)",
02910 ChanServ, from, chan->name);
02911 } else {
02912 sSend
02913 (":%s NOTICE %s :You are an oper but not a channel op, to override MKICK limitations, use -o",
02914 ChanServ, from);
02915 return RET_FAIL;
02916 }
02917 } else {
02918 sSend
02919 (":%s NOTICE %s :You are an oper but not a channel op, to override MKICK limitations, use -o",
02920 ChanServ, from);
02921 return RET_FAIL;
02922 }
02923 }
02924
02925 createGhostChannel(chan->name);
02926 sSend(":%s MODE %s +b *!*@*", ChanServ, chan->name);
02927 timer(10, deleteTimedGhostChannel, strdup(chan->name));
02928
02929 sendToChanOpsAlways(chan, "%s!%s is using MKICK on %s", accNick, nick->nick, from, chan->name);
02930
02931 for (tmp = chan->firstUser; tmp; tmp = next) {
02932 next = tmp->next;
02933
02934 sSend(":%s KICK %s %s", ChanServ, chan->name, tmp->person->nick);
02935 delChanUser(chan, tmp, 1);
02936 }
02937 return RET_OK;
02938 }
02939
02940
02941
02947 void sendChannelInfo(UserList *nick, RegChanList *chan, int fTerse)
02948 {
02949 char *from = nick->nick;
02950 char buf[IRCBUF];
02951 char timejunk[80];
02952 char modestring[20];
02953 const char *tmpcChar;
02954 unsigned int i;
02955 int hidden_details = 0;
02956 RegNickList *founderInfo;
02957
02958 struct {
02959 flag_t flags;
02960 const char *brief, *alt;
02961 const char *line;
02962 }
02963 csflagOptTab[] = {
02964 { CIDENT, "ident", "Ident", "Ident. Ops must identify to their nick before being recognised by ChanServ" },
02965 { COPGUARD, "opguard", "SecuredOps", "Op Guard. Only users in ChanServ's op list can have ops in the channel" },
02966 { CKTOPIC, "keeptopic", "\"Sticky\" Topics", "Preserve Topic. ChanServ will remember and re-set the last topic when the channel is empty" },
02967 { CPROTOP, "protect ops", NULL, "Protected Ops. Ops cannot be deopped by another op with lower access" },
02968 { CQUIET, "quiet", "Quiet", "Quiet Changes. ChanServ will not inform channel ops when channel options are changed" },
02969 { CHOLD, "\2held\2", "held", "Held. This channel will not expire." },
02970 };
02971
02972 if ((chan->mlock & (PM_S)) || (chan->flags & (CBANISH)))
02973 hidden_details = 2;
02974 else if ((chan->mlock & (PM_I)) || (chan->mlock & (PM_K)))
02975 hidden_details = 1;
02976
02977 if (hidden_details) {
02978 if (isOper(nick) ||
02979 getMiscChanOp(chan, nick->nick, 1, NULL) >= MAOP)
02980 hidden_details = 0;
02981 }
02982
02983 if ((chan->flags & CBANISH))
02984 sSend(":%s NOTICE %s :%s is BANISHED.", ChanServ, from, chan->name);
02985 else if ((chan->flags & CCLOSE))
02986 sSend(":%s NOTICE %s :\2This channel is CLOSED\2", ChanServ, from);
02987 else
02988 {
02989 founderInfo = chan->founderId.getNickItem();
02990
02991 switch(fTerse)
02992 {
02993 case 2:
02994 sSend(":%s NOTICE %s :\2***\2 Info on %s",
02995 ChanServ, from, chan->name);
02996 break;
02997 case 1:
02998 sSend(":%s NOTICE %s :Information on %s (terse):",
02999 ChanServ, from, chan->name);
03000 break;
03001 case 0: default:
03002
03003 sSend(":%s NOTICE %s :Information on %s:",
03004 ChanServ, from, chan->name);
03005 break;
03006 }
03007
03008 if (founderInfo != NULL)
03009 {
03010 #if defined(NETNICK) && defined(NETNICKFOUNDERLINE)
03011 if (strcasecmp(founderInfo->nick, NETNICK) == 0)
03012 {
03013 sSend(":%s NOTICE %s :Founder : %s", ChanServ, from, NETNICKFOUNDERLINE);
03014 }
03015 else
03016 #endif
03017 sSend(":%s NOTICE %s :Founder : %s (%s@%s)", ChanServ, from, founderInfo->nick, founderInfo->user, regnick_ugethost(nick, founderInfo));
03018 }
03019 else if ((tmpcChar = chan->founderId.getNick()) != NULL) {
03020 if (*tmpcChar != '\0' && *tmpcChar != '*')
03021 sSend(":%s NOTICE %s :Founder : %s", ChanServ, from, tmpcChar);
03022 }
03023
03024 if (chan->desc[0] != '\0')
03025 sSend(":%s NOTICE %s :Description: %s", ChanServ, from,
03026 chan->desc);
03027
03029 if (!hidden_details && chan->autogreet != NULL)
03030 sSend(":%s NOTICE %s :Autogreet : %s", ChanServ, from,
03031 chan->autogreet);
03032
03033 if ((hidden_details < 2) && chan->topic) {
03034 sSend(":%s NOTICE %s :Topic : %s (%s)", ChanServ, from,
03035 chan->topic, chan->tsetby);
03036 }
03037 if (chan->url)
03038 sSend(":%s NOTICE %s :Url : %s", ChanServ, from, chan->url);
03039 buf[0] = '\0';
03040
03041 if (!fTerse)
03042 sSend(":%s NOTICE %s :Options:", ChanServ, from);
03043
03044 for(i = 0; i < sizeof(csflagOptTab) / sizeof(csflagOptTab[0]); i++)
03045 {
03046 if ((chan->flags & csflagOptTab[i].flags) == csflagOptTab[i].flags)
03047 {
03048 if (fTerse)
03049 {
03050 if (buf[0] != '\0')
03051 strcat(buf, ", ");
03052 if (fTerse == 2 && csflagOptTab[i].alt)
03053 strcat(buf, csflagOptTab[i].alt);
03054 else
03055 strcat(buf, csflagOptTab[i].brief);
03056 }
03057 else
03058 sSend(":%s NOTICE %s :%s", ChanServ, from, csflagOptTab[i].line);
03059
03060 }
03061 }
03062
03063 if (fTerse)
03064 {
03065 if (fTerse == 2) {
03066 if (chan->restrictlevel)
03067 sprintf(buf + strlen(buf), "%sRestricted(%d)",
03068 buf[0] != '\0' ? ", " : "", chan->restrictlevel);
03069 if (chan->tlocklevel > AOP)
03070 sprintf(buf + strlen(buf), "%sTopic Lock(%d)",
03071 buf[0] != '\0' ? ", " : "", chan->tlocklevel);
03072 }
03073 sSend(":%s NOTICE %s :Options : %s", ChanServ, from, buf);
03074 if (chan->memolevel > 0)
03075 sSend(":%s NOTICE %s :Memo Level : %s", ChanServ, from, opLevelName(chan->memolevel, 0));
03076 }
03077
03078 makeModeLockStr(chan, modestring);
03079
03080 if (fTerse)
03081 {
03082 if (fTerse != 2)
03083 {
03084 if (*modestring != '\0')
03085 sSend(":%s NOTICE %s :Mode Locked to: \002%s\002", ChanServ, from,
03086 modestring);
03087 sSend(":%s NOTICE %s :Topic Lock: Level %2i+, Restricted: Level %2i+",
03088 ChanServ, from, chan->tlocklevel, chan->restrictlevel);
03089 }
03090 else {
03091 if (*modestring != '\0')
03092 sSend(":%s NOTICE %s :Mode Lock : %s", ChanServ, from,
03093 modestring);
03094 }
03095 }
03096 else
03097 {
03098 if (*modestring == '\0')
03099 strcpy(modestring, "(none)");
03100
03101 sSend
03102 (":%s NOTICE %s :Mode Locked to: \002%s\002 = These modes will be enforced on the channel",
03103 ChanServ, from, modestring);
03104
03105 sSend(":%s NOTICE %s :Topic Lock: \002Level %i+\002 = %s",
03106 ChanServ, from, chan->tlocklevel,
03107 (chan->tlocklevel == 0) ? "Any channel operator can change the topic" :
03108 "Only operators with this access level or higher can change the topic");
03109 sSend(":%s NOTICE %s :Restrict Lock: \002Level %i+\002 = %s",
03110 ChanServ, from, chan->restrictlevel,
03111 (chan->restrictlevel == 0) ? "Anyone can join this channel" :
03112 "Only operators with this access level or higher can join");
03113 }
03114
03115 if (strftime(timejunk, 80, "%a %Y-%b-%d %T %Z",
03116 localtime(&chan->timereg)) > 0)
03117 {
03118 if (fTerse != 2)
03119 sSend(":%s NOTICE %s :Channel registered at: %s", ChanServ, from,
03120 timejunk);
03121 else
03122 sSend(":%s NOTICE %s :Registered : %s", ChanServ, from,
03123 timejunk);
03124 }
03125
03126 if (strftime(timejunk, 80, "%a %Y-%b-%d %T %Z",
03127 localtime(&chan->timestamp)) > 0)
03128 {
03129 if (fTerse != 2)
03130 sSend(":%s NOTICE %s :Channel last used: %s", ChanServ, from,
03131 timejunk);
03132 else
03133 sSend(":%s NOTICE %s :Last Used : %s", ChanServ, from,
03134 timejunk);
03135 }
03136 }
03137
03138 if (isOper(nick)) {
03139 sSend(":%s NOTICE %s :+ Oper Info: %i Ops %i Akicks", ChanServ, from,
03140 chan->ops, chan->akicks);
03141
03142 if (chan->flags & CMARK) {
03143 sSend(":%s NOTICE %s :+ Channel MARKED%s%s.", ChanServ, from,
03144 chan->markby ? " by " : "",
03145 chan->markby ? chan->markby : "");
03146 }
03147 }
03148
03149
03150
03151
03152 if (fTerse != 2)
03153 sSend(":%s NOTICE %s :End of information on %s", ChanServ, from,
03154 chan->name);
03155 else
03156 sSend(":%s NOTICE %s :\2***\2 End of info", ChanServ, from);
03157 }
03158
03170 CCMD(cs_info)
03171 {
03172 char *from = nick->nick;
03173 RegChanList *chan;
03174 int i, fTerse;
03175
03176 if (addFlood(nick, 5))
03177 return RET_KILLED;
03178
03179 fTerse = (nick->reg && (nick->reg->flags & NTERSE));
03180
03181 for(i = 1; i < numargs; i++) {
03182 if (args[i][0] != '-')
03183 break;
03184 if (strcmp(args[i], "-long") == 0 || strcmp(args[i], "-verbose") == 0)
03185 fTerse = 0;
03186 else if (strcmp(args[i], "-terse") == 0 || strcmp(args[i], "-short") == 0)
03187 fTerse = 1;
03188 else if (strcmp(args[i], "-2") == 0)
03189 fTerse = 2;
03190 }
03191
03192 if (i >= numargs) {
03193 sSend(":%s NOTICE %s :You must specify a channel", ChanServ, from);
03194 return RET_SYNTAX;
03195 }
03196
03197 chan = getRegChanData(args[i]);
03198
03199 if (!chan) {
03200 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
03201 args[i]);
03202 return RET_NOTARGET;
03203 }
03204
03205
03206
03207
03208 sendChannelInfo(nick, chan, fTerse);
03209
03210 return RET_OK;
03211 }
03212
03213
03214
03225 CCMD(cs_access)
03226 {
03227 char *from = nick->nick;
03228 char checkAccessNick[NICKLEN + 1];
03229 RegChanList *tmp;
03230 UserList *tmpnick;
03231 RegNickList *tmprnick;
03232 int level;
03233
03234 if (numargs < 2) {
03235 sSend(":%s NOTICE %s :You must specify at least a channel",
03236 ChanServ, from);
03237 return RET_SYNTAX;
03238 }
03239
03240 tmp = getRegChanData(args[1]);
03241
03242 if (!tmp) {
03243 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
03244 args[1]);
03245 return RET_NOTARGET;
03246 }
03247
03248 if (numargs >= 3)
03249 if (getNickData(args[2]) == NULL) {
03250 sSend(":%s NOTICE %s :%s is not online", ChanServ, from,
03251 args[2]);
03252 return RET_NOTARGET;
03253 }
03254
03255 level =
03256 getMiscChanOp(tmp, (numargs >= 3) ? args[2] : nick->nick,
03257 ChanGetIdent(tmp), checkAccessNick);
03258 tmpnick = getNickData((numargs >= 3) ? args[2] : nick->nick);
03259 tmprnick = getRegNickData(checkAccessNick);
03260
03261 if (level == FOUNDER && *checkAccessNick == '*')
03262 sSend(":%s NOTICE %s :%s %s identified as the founder of %s",
03263 ChanServ, from, (numargs >= 3) ? args[2] : "You",
03264 (numargs >= 3) ? "is" : "are", tmp->name);
03265 else if (level < 1)
03266 sSend(":%s NOTICE %s :%s %s access level %i on %s", ChanServ, from,
03267 (numargs >= 3) ? args[2] : "You",
03268 (numargs >= 3) ? "has" : "have", level, tmp->name);
03269 else if (tmprnick && tmpnick && isIdentified(tmpnick, tmprnick))
03270 sSend
03271 (":%s NOTICE %s :%s %s access level %i on %s via identification to %s",
03272 ChanServ, from, (numargs >= 3) ? args[2] : "You",
03273 (numargs >= 3) ? "has" : "have", level, tmp->name,
03274 checkAccessNick);
03275 else
03276 sSend
03277 (":%s NOTICE %s :%s %s access level %i on %s from access list of %s",
03278 ChanServ, from, (numargs >= 3) ? args[2] : "You",
03279 (numargs >= 3) ? "has" : "have", level, tmp->name,
03280 checkAccessNick);
03281 return RET_OK;
03282 }
03283
03284
03285
03290 CCMD(cs_register)
03291 {
03292 char *from = nick->nick;
03293 char descbuf[IRCBUF];
03294 char pw_reason[IRCBUF];
03295 cNickList *tmp;
03296 cAccessList *founder;
03297 ChanList *chan;
03298 RegChanList *reg;
03299 int override = 0;
03300
03301 if (numargs < 4) {
03302 sSend
03303 (":%s NOTICE %s :You must specify a channel, a password, and a description for that channel to register it",
03304 ChanServ, from);
03305 sSend
03306 (":%s NOTICE %s :See \2/msg %s HELP REGISTER\2 for more information",
03307 ChanServ, from, ChanServ);
03308 return RET_SYNTAX;
03309 }
03310
03311 chan = getChanData(args[1]);
03312 tmp = getChanUserData(chan, nick);
03313
03314 if (!ValidChannelName(args[1])) {
03315 sSend(":%s NOTICE %s :Invalid channel name, %s.", ChanServ, from,
03316 args[1]);
03317 return RET_EFAULT;
03318 }
03319
03320 if (!nick || !nick->reg || !isIdentified(nick, nick->reg)) {
03321 sSend
03322 (":%s NOTICE %s :You must be identified to register a channel",
03323 NickServ, from);
03324 return RET_FAIL;
03325 }
03326
03327 if (chan && chan->reg) {
03328 sSend(":%s NOTICE %s :%s is already registered", ChanServ, from,
03329 args[1]);
03330 return RET_FAIL;
03331 }
03332
03333 if (is_sn_chan(args[1]) && !opFlagged(nick, OOPER | OVERRIDE)) {
03334 sSend(":%s NOTICE %s :This channel is reserved for " NETWORK ".",
03335 ChanServ, from);
03336 return RET_NOPERM;
03337 }
03338
03339 if (isPasswordAcceptable(args[2], pw_reason) == 0) {
03340 sSend(":%s NOTICE %s :Sorry, %s isn't a password that you can use.",
03341 ChanServ, from, args[1]);
03342 sSend(":%s NOTICE %s :%s", ChanServ, from, pw_reason);
03343 return RET_EFAULT;
03344 }
03345
03346 if (PASSLEN < strlen(args[2])) {
03347 sSend
03348 (":%s NOTICE %s :Your password is too long, it must be %d characters or less",
03349 ChanServ, from, PASSLEN);
03350 return RET_EFAULT;
03351 }
03352
03353 #if CHANDESCBUF < IRCBUF
03354 parse_str(args, numargs, 3, descbuf, CHANDESCBUF + 1);
03355 #else
03356 parse_str(args, numargs, 3, descbuf, IRCBUF);
03357 #endif
03358
03359 if (strlen(descbuf) >= CHANDESCBUF) {
03360 sSend(":%s NOTICE %s :Your description is too long, it must be %d characters or less.",
03361 ChanServ, from, CHANDESCBUF - 1);
03362 return RET_EFAULT;
03363 }
03364
03365 if (nick->reg->chans >= ChanLimit && !opFlagged(nick, OVERRIDE)) {
03366 sSend(":%s NOTICE %s :You have registered too many channels",
03367 ChanServ, from);
03368 #ifdef REGLIMITYELL
03369 sSend(":%s GLOBOPS :%s is trying to register too many channels",
03370 ChanServ, from);
03371 #endif
03372 return RET_FAIL;
03373 }
03374
03375 if (!chan || !tmp || !tmp->op) {
03376 if (!opFlagged(nick, OVERRIDE | OSERVOP)
03377 && !opFlagged(nick, OVERRIDE | ODMOD)) {
03378 sSend
03379 (":%s NOTICE %s :You must be both inside, and oped, in the channel you wish to register",
03380 ChanServ, from);
03381 return RET_FAIL;
03382 }
03383 }
03384
03385 if ((override = opFlagged(nick, OVERRIDE))) {
03386 sSend(":%s NOTICE %s :Override registration ok.", ChanServ, from);
03387 sSend(":%s GLOBOPS :%s used override register on channel %s",
03388 ChanServ, from, args[1]);
03389 }
03390
03391 nick->reg->chans++;
03392 reg = (RegChanList *) oalloc(sizeof(RegChanList));
03393 initRegChanData(reg);
03394 chan->reg = reg;
03395 strcpy(reg->name, chan->name);
03396 reg->founderId = nick->reg->regnum;
03397 reg->flags |= CENCRYPT;
03398 pw_enter_password(args[2], reg->password, ChanGetEnc(reg));
03399
03400 reg->timereg = CTime;
03401 reg->timestamp = CTime;
03402 sendToChanOpsAlways(chan, "%s just registered %s", from, args[1]);
03403 sSend
03404 (":%s NOTICE %s :%s is now registered under your nick: \002%s\002",
03405 ChanServ, from, args[1], from);
03406 sSend(":%s NOTICE %s :You now have level 15 access.", ChanServ, from);
03407 sSend(":%s NOTICE %s :Your password is \002%s\002 DO NOT FORGET IT",
03408 ChanServ, from, args[2]);
03409 sSend(":%s NOTICE %s :We are NOT responsible for lost passwords.",
03410 ChanServ, from);
03411 sSend(":%s NOTICE %s :Your channel is modelocked +tn-k", ChanServ,
03412 from);
03413 sSend(":%s NOTICE %s :And topic preservation is set on", ChanServ,
03414 from);
03415 sSend
03416 (":%s NOTICE %s :For information on channel maintenance, /msg %s HELP",
03417 ChanServ, from, ChanServ);
03418 founder = (cAccessList *) oalloc(sizeof(cAccessList));
03419 founder->nickId = nick->reg->regnum;
03420 founder->uflags = FOUNDER;
03421
03422 addChanOp(chan->reg, founder);
03423 chan->reg->flags |= CKTOPIC;
03424 chan->reg->flags |= CIDENT;
03425 chan->reg->mlock |= PM_N;
03426 chan->reg->mlock |= PM_T;
03427 chan->reg->mlock |= MM_H;
03428 chan->reg->mlock |= MM_K;
03429 chan->reg->facc = 1;
03430 addRegChan(reg);
03431 mostchans++;
03432 chanlog->log(nick, CS_REGISTER, chan->name, 0,
03433 override ? "(override)" : "");
03434 strncpyzt(chan->reg->desc, descbuf, CHANDESCBUF);
03435 return RET_OK_DB;
03436 }
03437
03438
03439
03450 CCMD(cs_identify)
03451 {
03452 char *from = nick->nick;
03453 RegChanList *chan;
03454 cAccessList *newitem;
03455
03456 if (numargs < 3) {
03457 sSend
03458 (":%s NOTICE %s :You must specify a channel and password to identify with",
03459 ChanServ, from);
03460 return RET_SYNTAX;
03461 }
03462 chan = getRegChanData(args[1]);
03463
03464 if (!chan) {
03465 sSend(":%s NOTICE %s :The channel is not registered.", ChanServ,
03466 from);
03467 return RET_NOTARGET;
03468 }
03469
03470 if ((chan->flags & (CBANISH | CCLOSE)) && !isRoot(nick)) {
03471 sSend(":%s NOTICE %s :You cannot identify to that channel because it is closed or banished.",
03472 ChanServ, from);
03473 return RET_FAIL;
03474 }
03475
03476 if ((chan->flags & CFORCEXFER)) {
03477 sSend(":%s NOTICE %s :An operator has disabled the current "
03478 "channel password for a forced change of founder.",
03479 ChanServ, from);
03480 return RET_FAIL;
03481 }
03482
03483 if (isMD5Key(args[2]))
03484 {
03485 struct auth_data auth_info[] = {{
03486 nick->auth_cookie,
03487 nick->idnum.getHashKey(),
03488 2
03489 }};
03490
03491 if (!Valid_md5key(args[2], auth_info, chan->name, chan->password, ChanGetEnc(chan)))
03492 {
03493 sSend(":%s NOTICE %s :Invalid MD5 key.", NickServ, nick->nick);
03494 nick->auth_cookie = 0;
03495 if (BadPwChan(nick, chan))
03496 return RET_KILLED;
03497
03498 return RET_BADPW;
03499 }
03500
03501
03502 nick->auth_cookie = 0;
03503 }
03504 else if (!Valid_pw(args[2], chan->password, ChanGetEnc(chan))) {
03505 sSend(":%s NOTICE %s :Invalid password", ChanServ, from);
03506
03507 if (!(chan->flags & CFORCEXFER)) {
03508 if (BadPwChan(nick, chan))
03509 return RET_KILLED;
03510 }
03511
03512 return RET_BADPW;
03513 }
03514
03516 if (nick->reg && nick->reg->regnum == chan->founderId)
03517 chan->facc = 1;
03518 else {
03519 if (chan->id.nick)
03520 FREE(chan->id.nick);
03521 chan->id.nick = (char *)oalloc(strlen(nick->nick) + 1);
03522 chan->id.timestamp = CTime;
03523 chan->id.idnum = nick->idnum;
03524 strcpy(chan->id.nick, nick->nick);
03525 chan->facc = 0;
03526 }
03527 chan->timestamp = CTime;
03528 sSend(":%s NOTICE %s :You are now the identified founder of %s",
03529 ChanServ, from, chan->name);
03530
03531
03532 if (!chan->facc)
03533 return RET_OK;
03534
03535 if (nick->reg && nick->caccess > 1)
03536 {
03537 newitem = getChanOpData(chan, from);
03538
03539 if (newitem == NULL) {
03540 newitem = (cAccessList *) oalloc(sizeof(cAccessList));
03541 newitem->uflags = FOUNDER;
03542 newitem->nickId = nick->reg->regnum;
03543 addChanOp(chan, newitem);
03544 } else if (newitem->uflags < FOUNDER)
03545 newitem->uflags = FOUNDER;
03546 }
03547
03548 GoodPwChan(nick, chan);
03549 chan->chpw_key = 0;
03550
03551 return RET_OK;
03552 }
03553
03554
03555
03562 CCMD(cs_addop)
03563 {
03564 char *from = nick->nick;
03565 RegChanList *chan;
03566 services_cmd_id thisCmd = CS_ADDOP;
03567 int targLevel;
03568
03569 if (tolower(*args[0]) == 'd')
03570 thisCmd = CS_DELOP;
03571
03572 if (numargs < 3) {
03573 if (thisCmd == CS_ADDOP)
03574 sSend(":%s NOTICE %s :You must specify both a channel to add "
03575 "to, and a nick for ADDOP.", ChanServ, from);
03576 else
03577 sSend
03578 (":%s NOTICE %s :You must specify both a channel to delete "
03579 "from, and a nickname to remove.", ChanServ, from);
03580 return RET_SYNTAX;
03581 }
03582
03583 chan = getRegChanData(args[1]);
03584 if (chan == NULL) {
03585 sSend(":%s NOTICE %s :%s channel is not registered.", ChanServ,
03586 from, args[1]);
03587 return RET_NOTARGET;
03588 }
03589
03590 targLevel = (numargs < 4) ? -1 : opNameLevel(args[3]);
03591
03592 if ((thisCmd == CS_ADDOP) && targLevel <= 0)
03593 targLevel = AOP;
03594
03595 return do_chanop(thisCmd, nick, chan, args[2], targLevel);
03596 }
03597
03607 static cmd_return do_chanop(services_cmd_id cmd,
03608 UserList * isfrom,
03609 RegChanList * chan,
03610 const char *cTargetNick,
03611 int tarLevel
03612 )
03613 {
03614 int mylevel;
03615
03616 if (!isfrom || !chan || (!cTargetNick && cmd != CS_LISTOP))
03617 return RET_FAIL;
03618 mylevel = getChanOp(chan, isfrom->nick);
03619
03620 if (isFounder(chan, isfrom))
03621 mylevel = FOUNDER;
03622
03623 if ((AOP > mylevel) && !opFlagged(isfrom, OOPER | OVERRIDE)) {
03624 sSend
03625 (":%s NOTICE %s :Your access is too low to modify the channel oplist.",
03626 ChanServ, isfrom->nick);
03627 return RET_NOPERM;
03628 }
03629
03630 if (chan->ops >= ChanMaxOps(chan) && (cmd == CS_ADDOP)
03631 && !opFlagged(isfrom, OVERRIDE)) {
03632 sSend(":%s NOTICE %s :%s has too many ops", ChanServ, isfrom->nick,
03633 chan->name);
03634 sSend(":%s GLOBOPS :%s tries to add too many ops to %s.", ChanServ, isfrom->nick, chan->name);
03635
03636 if (addFlood(isfrom, 10))
03637 return RET_KILLED;
03638
03639 return RET_FAIL;
03640 }
03641
03642 if (!opFlagged(isfrom, OVERRIDE | ODMOD | OOPER)
03643 && getChanOpId(chan, isfrom->nick) < AOP) {
03644 sSend
03645 (":%s NOTICE %s :You must identify to modify channel op lists.",
03646 ChanServ, isfrom->nick);
03647 return RET_NOPERM;
03648 }
03649
03650 switch (cmd) {
03651 default:
03652 break;
03653 case CS_ADDOP:
03654 return do_chanop_add(isfrom, chan, cTargetNick, tarLevel);
03655 break;
03656 case CS_DELOP:
03657 return do_chanop_del(isfrom, chan, cTargetNick, tarLevel);
03658 break;
03659 case CS_LISTOP:
03660 return do_chanop_list(isfrom, chan, cTargetNick, tarLevel);
03661 break;
03662 }
03663
03664 return RET_FAIL;
03665 }
03666
03675 static cmd_return do_chanop_add(UserList * isfrom,
03676 RegChanList * chan,
03677 const char *cTargetNick,
03678 int tarLevel
03679 )
03680 {
03681 const char *from = isfrom->nick;
03682 char accNick[NICKLEN+1];
03683 cAccessList *targetEntry, *anop;
03684 RegNickList *tarRegNick;
03685 int currentlevel;
03686 int maxEdit = FOUNDER;
03687
03688 int mylevel = getMiscChanOp(chan, isfrom->nick, ChanGetIdent(chan), accNick);
03689
03690 if ((mylevel < FOUNDER) && isOper(isfrom) && cTargetNick
03691 && opFlagged(isfrom, ODMOD | OVERRIDE)) {
03692 sSend(":%s GLOBOPS :%s using override add on %s",
03693 ChanServ, isfrom->nick, chan->name);
03694 mylevel = FOUNDER + 1;
03695 }
03696 targetEntry = getChanOpData(chan, cTargetNick);
03697 tarRegNick = getRegNickData(cTargetNick);
03698
03699 if (tarRegNick == NULL) {
03700 sSend
03701 (":%s NOTICE %s :The nickname %s is not registered, nicknames must be registered to add as ops",
03702 ChanServ, from, cTargetNick);
03703 return RET_NOTARGET;
03704 }
03705
03706 if (mylevel <= AOP)
03707 maxEdit = 0;
03708 else if (mylevel < MSOP)
03709 maxEdit = 1;
03710 else if (mylevel < SOP)
03711 maxEdit = MAOP;
03712 else if (mylevel < FOUNDER)
03713 maxEdit = mylevel - 1;
03714 else
03715 maxEdit = mylevel;
03716
03717 if (targetEntry) {
03718 if (tarLevel == -1) {
03719 sSend(":%s NOTICE %s :%s is already in the channel %s "
03720 "list, and you did not specify a valid level to change"
03721 " them to.", ChanServ, isfrom->nick,
03722 opLevelName(tarLevel, 0), cTargetNick);
03723 return RET_FAIL;
03724 }
03725
03726 if (tarLevel < 1 || tarLevel > FOUNDER) {
03727 sSend
03728 (":%s NOTICE %s :The level you specified (%d) is not a valid level",
03729 ChanServ, from, tarLevel);
03730 return RET_EFAULT;
03731 }
03732
03733 if ((anop = getChanOpData(chan, cTargetNick)))
03734 currentlevel = anop->uflags;
03735 else
03736 currentlevel = 0;
03737
03738 if ((!opFlagged(isfrom, ODMOD | OVERRIDE)
03739 && !isFounder(chan, isfrom)) && mylevel != FOUNDER) {
03740 if (maxEdit >= mylevel)
03741 maxEdit = mylevel - 1;
03742
03743 if (mylevel < tarLevel || maxEdit < tarLevel) {
03744 sSend
03745 (":%s NOTICE %s :A%s %s cannot promote an operator to level %s.",
03746 ChanServ, from, mylevel == MAOP ? "n" : "",
03747 opLevelName(mylevel, 2), opLevelName(tarLevel, 2));
03748 return RET_NOPERM;
03749 }
03750
03751 if (maxEdit < currentlevel || mylevel < currentlevel) {
03752 sSend
03753 (":%s NOTICE %s :A%s %s cannot modify the access level of a%s %s.",
03754 ChanServ, from, mylevel == 5 ? "n" : "",
03755 opLevelName(mylevel, 2),
03756 currentlevel == MAOP ? "n" : "",
03757 opLevelName(currentlevel, 2));
03758 return RET_NOPERM;
03759 }
03760 }
03761
03762
03763
03764 sSend(":%s NOTICE %s :%s was %s from %s to %s.", ChanServ, from,
03765 cTargetNick,
03766 ((tarLevel > targetEntry->uflags) ? "promoted" : "demoted"),
03767 opLevelName(targetEntry->uflags, 2), opLevelName(tarLevel,
03768 2));
03769
03770 targetEntry->uflags = tarLevel;
03771 return RET_OK_DB;
03772 }
03773
03774 if (tarLevel == -1)
03775 tarLevel = MAOP;
03776
03777 if ((!opFlagged(isfrom, ODMOD | OVERRIDE) && !isFounder(chan, isfrom)
03778 && mylevel != FOUNDER)) {
03779 if (maxEdit >= FOUNDER)
03780 maxEdit = FOUNDER - 1;
03781 }
03782
03783 if (tarLevel > maxEdit) {
03784 sSend
03785 (":%s NOTICE %s :Permission denied -- you cannot add ops at levels higher than %s (%d).",
03786 ChanServ, from, opLevelName(maxEdit, 2), maxEdit);
03787 return RET_NOPERM;
03788 }
03789
03790 if ((tarRegNick->flags & NOADDOP) &&
03791 (!isOper(isfrom) ||
03792 (!opFlagged(isfrom, OVERRIDE | OSERVOP)
03793 && !opFlagged(isfrom, OVERRIDE | ODMOD))) ) {
03794 sSend
03795 (":%s NOTICE %s :The nickname %s has set a feature which disallows the adding of this nickname to an oplist.",
03796 ChanServ, from, cTargetNick);
03797 return RET_NOPERM;
03798 }
03799
03800 targetEntry = (cAccessList *) oalloc(sizeof(cAccessList));
03801
03802 if (tarLevel < 1 || tarLevel > FOUNDER) {
03803 sSend
03804 (":%s NOTICE %s :The level you specified (%d) is not a valid level",
03805 ChanServ, from, tarLevel);
03806 FREE(targetEntry);
03807 return RET_EFAULT;
03808 }
03809
03810 if (!tarLevel)
03811 targetEntry->uflags = AOP;
03812 else
03813 targetEntry->uflags = tarLevel;
03814
03815 targetEntry->nickId = tarRegNick->regnum;
03816 sSend(":%s NOTICE %s :Added op(%i) %s(%i)", ChanServ, from,
03817 chan->ops + 1, cTargetNick, targetEntry->uflags);
03818 sendToChanOps(getChanData(chan->name), "%s!%s added op %s(%i)",
03819 accNick, from, cTargetNick,
03820 targetEntry->uflags);
03821 addChanOp(chan, targetEntry);
03822 return RET_OK_DB;
03823 }
03824
03833 static cmd_return do_chanop_del(UserList * isfrom, RegChanList * chan,
03834 const char *cTargetNick, int tarLevel)
03835 {
03836 char *from = isfrom->nick;
03837 cAccessList *delop;
03838 const char *tmpNick;
03839 int a, x;
03840 int maxEdit = FOUNDER;
03841
03842 if ((x = atoi(cTargetNick))) {
03843 for (delop = chan->firstOp; delop; delop = delop->next) {
03844 if (tarLevel != delop->uflags && tarLevel != -1)
03845 continue;
03846 if (delop->index == x)
03847 break;
03848 }
03849 if (delop == NULL) {
03850 sSend
03851 (":%s NOTICE %s :%s is not an index in the %s list for %s",
03852 ChanServ, from, cTargetNick,
03853 tarLevel == -1 ? "ops" : opLevelName(tarLevel, 2),
03854 chan->name);
03855 return RET_NOTARGET;
03856 }
03857 } else {
03858 delop = getChanOpData(chan, cTargetNick);
03859 if (delop && tarLevel != -1 && tarLevel != delop->uflags)
03860 delop = NULL;
03861 }
03862
03863 if (delop == NULL) {
03864 sSend(":%s NOTICE %s :%s is not in the %s list for %s", ChanServ,
03865 from, cTargetNick,
03866 tarLevel == -1 ? "ops" : opLevelName(tarLevel, 2),
03867 chan->name);
03868 return RET_NOTARGET;
03869 }
03870
03871 a = getChanOp(chan, from);
03872
03873 if (opFlagged(isfrom, OOPER | ODMOD | OVERRIDE)) {
03874 sSend(":%s GLOBOPS :%s using directmod on %s (delop %s [%d])",
03875 ChanServ, isfrom->nick, chan->name, cTargetNick, tarLevel);
03876 a = FOUNDER;
03877 }
03878
03879 if (a < AOP)
03880 maxEdit = 0;
03881 else if (a < MSOP)
03882 maxEdit = 1;
03883 else if (a < SOP)
03884 maxEdit = MAOP;
03885 else if (a < FOUNDER)
03886 maxEdit = a - 1;
03887 else
03888 maxEdit = a;
03889
03890 if ((delop->uflags > maxEdit) && (!isfrom->reg || delop->nickId != isfrom->reg->regnum)) {
03891
03892
03893
03894
03895
03896
03897 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
03898 return RET_NOPERM;
03899 }
03900
03901 tmpNick = delop->nickId.getNick();
03902
03903 if (tmpNick)
03904 {
03905 sendToChanOps(getChanData(chan->name), "%s deleted op %s(%i)", from,
03906 tmpNick, delop->uflags);
03907 sSend(":%s NOTICE %s :Deleted op %s on %s", ChanServ, from,
03908 tmpNick, chan->name);
03909 }
03910 else {
03911 sendToChanOps(getChanData(chan->name), "%s deleted op %s(%i)", from,
03912 "*deactivated*", delop->uflags);
03913 }
03914
03915 delChanOp(chan, delop);
03916 return RET_OK_DB;
03917 }
03918
03919
03928 static cmd_return do_chanop_list(UserList * isfrom, RegChanList * chan,
03929 const char *cTargetNick, int tarLevel)
03930 {
03931 cAccessList *tmp;
03932 const char *from = isfrom->nick;
03933 const char *tmpName;
03934 RegNickList *tmpOpRnl;
03935 MaskData *tmpMask = NULL;
03936 int i = 0, x = 0;
03937
03938 if (cTargetNick)
03939 {
03940 tmpMask = make_mask();
03941
03942 if (split_userhost(cTargetNick, tmpMask) < 0)
03943 {
03944 free_mask(tmpMask);
03945 tmpMask = NULL;
03946 }
03947 }
03948
03949 if (tarLevel == -1)
03950 {
03951 sSend(":%s NOTICE %s : %-3s Listing For %s", ChanServ, from,
03952 "Op", chan->name);
03953 sSend(":%s NOTICE %s :(Index) (Level) (Nick)", ChanServ, from);
03954 }
03955 else {
03956 sSend(":%s NOTICE %s :%s Search results for channel %s", ChanServ, from,
03957 opLevelName(tarLevel, 2), chan->name);
03958 }
03959
03960
03961
03962 for (tmp = chan->firstOp; tmp; tmp = tmp->next, i++) {
03963 if (!(tarLevel == -1 || tmp->uflags == tarLevel))
03964 continue;
03965 tmpOpRnl = (tmp->nickId).getNickItem();
03966 tmpName = tmpOpRnl ? tmpOpRnl->nick : "*deactivated*";
03967
03968 if (cTargetNick && match(cTargetNick, tmpName))
03969 {
03970 if (tmpMask == NULL || tmpOpRnl == NULL)
03971 continue;
03972
03973 if (match(tmpMask->nick, tmpOpRnl->nick) ||
03974 match(tmpMask->user, tmpOpRnl->user) ||
03975 match(tmpMask->host, regnick_ugethost(isfrom, tmpOpRnl, 0)))
03976 continue;
03977 }
03978
03979 if (tarLevel == -1)
03980 {
03981 sSend(":%s NOTICE %s :(%-3i) (%-4i) (%-30s)", ChanServ, from,
03982 tmp->index, tmp->uflags, tmpName);
03983 }
03984 else
03985 {
03986 if (tmpOpRnl)
03987 sSend(":%s NOTICE %s :%4i %s (%s@%s)", ChanServ, from,
03988 tmp->index, tmpName, tmpOpRnl->user, regnick_ugethost(isfrom, tmpOpRnl));
03989 else
03990 sSend(":%s NOTICE %s :%4i %s", ChanServ, from,
03991 tmp->index, tmpName);
03992 }
03993
03994
03995 x++;
03996 }
03997
03998 if (tarLevel == -1) {
03999 sSend(":%s NOTICE %s :%i op elements searched", ChanServ, from, i);
04000 sSend(":%s NOTICE %s :%i matched given conditions", ChanServ, from, x);
04001 }
04002 else {
04003 sSend(":%s NOTICE %s :[%i match(es) found]", ChanServ, from, x);
04004 }
04005
04006 if (tmpMask) {
04007 free_mask(tmpMask);
04008 }
04009
04010 return RET_OK;
04011 }
04012
04013
04014
04018 int cleanChopList(RegChanList *chan)
04019 {
04020 cAccessList *delbad, *delbad_next;
04021 int removedBad = 0;
04022
04023 for(delbad = chan->firstOp; delbad; delbad = delbad_next) {
04024 delbad_next = delbad->next;
04025
04026 if (!delbad->nickId.getNick()) {
04027 delChanOp(chan, delbad);
04028 ++removedBad;
04029 }
04030 }
04031
04032 return removedBad;
04033 }
04034
04039 CCMD(cs_clean)
04040 {
04041 char *from = nick->nick;
04042 RegChanList *chan;
04043 int removedBad = 0, aclvl;
04044
04045 if (numargs < 2) {
04046 sSend(":%s NOTICE %s :You must specify a channel", ChanServ, from);
04047 return RET_SYNTAX;
04048 }
04049
04050 chan = getRegChanData(args[1]);
04051
04052 if (chan == NULL) {
04053 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
04054 args[1]);
04055 return RET_NOTARGET;
04056 }
04057
04058 aclvl = getChanOp(chan, from);
04059
04060 if ((MSOP > aclvl) && (!isOper(nick))) {
04061 sSend
04062 (":%s NOTICE %s :You must be at least level %i in the channel op list to CLEAN.",
04063 ChanServ, from, MSOP);
04064 return RET_NOPERM;
04065 }
04066
04067 removedBad = cleanChopList(chan);
04068
04069 if (removedBad)
04070 {
04071 sSend(":%s NOTICE %s :Removed %d chanop entries that were no longer valid.",
04072 ChanServ, from, removedBad);
04073 return RET_OK_DB;
04074 }
04075 else
04076 {
04077 sSend(":%s NOTICE %s :No bad op entries found.",
04078 ChanServ, from);
04079 return RET_OK_DB;
04080 }
04081 }
04082
04087 CCMD(cs_addak)
04088 {
04089 char *from = nick->nick;
04090 cAkickList *newitem;
04091 RegChanList *chan;
04092 int i;
04093
04094 if (numargs < 3) {
04095 sSend
04096 (":%s NOTICE %s :You must specify both a channel to add to, and a mask for ADDAK",
04097 ChanServ, from);
04098 return RET_SYNTAX;
04099 }
04100
04101 chan = getRegChanData(args[1]);
04102 if (!chan) {
04103 sSend
04104 (":%s NOTICE %s :The channel must be registered to allow addition/removal of akicks",
04105 ChanServ, from);
04106 return RET_FAIL;
04107 }
04108
04109 if (MSOP > getChanOp(chan, from)
04110 && (!opFlagged(nick, OVERRIDE | ODMOD | OOPER))) {
04111 sSend(":%s NOTICE %s :Your access is too low to add akicks",
04112 ChanServ, from);
04113 return RET_NOPERM;
04114 }
04115
04116 if (chan->akicks >= (int)ChanMaxAkicks(chan) && (!opFlagged(nick, OVERRIDE))) {
04117 sSend(":%s NOTICE %s :%s has too many akicks", ChanServ, from,
04118 chan->name);
04119 sSend(":%s GLOBOPS :%s tries to add too many akicks to %s.", ChanServ, from, chan->name);
04120
04121 if (addFlood(nick, 10))
04122 return RET_KILLED;
04123 return RET_FAIL;
04124 }
04125 newitem = getChanAkick(chan, args[2]);
04126 if (newitem) {
04127 sSend(":%s NOTICE %s :%s is already in the akick list", ChanServ,
04128 from, args[2]);
04129 return RET_FAIL;
04130 }
04131 if (!index(args[2], '!') || !index(args[2], '@')) {
04132 sSend(":%s NOTICE %s :Invalid AKick mask %s", ChanServ, from,
04133 args[2]);
04134 return RET_EFAULT;
04135 }
04136
04137 newitem = (cAkickList *) oalloc(sizeof(cAkickList));
04138 strncpyzt(newitem->mask, args[2], USERLEN + HOSTLEN + 2);
04139 snprintf(newitem->reason, 51 + NICKLEN, "%s:", from);
04140 for (i = 3;
04141 i < numargs
04142 && (strlen(newitem->reason) + strlen(args[i]) + 2) <= NICKLEN + 51; i++) {
04143 strcat(newitem->reason, " ");
04144 strcat(newitem->reason, args[i]);
04145 }
04146 newitem->added = CTime;
04147 addChanAkick(chan, newitem);
04148 sendToChanOps(getChanData(chan->name), "%s added akick %s (%s)", from,
04149 newitem->mask, newitem->reason);
04150 sSend(":%s NOTICE %s :Added Akick %s to %s", ChanServ, from,
04151 newitem->mask, chan->name);
04152 return RET_OK_DB;
04153 }
04154
04159 CCMD(cs_wipeak)
04160 {
04161 char *from = nick->nick;
04162 RegChanList *chan;
04163 cAkickList *curr_akick;
04164 cAkickList *next_akick;
04165
04166
04167 if (numargs < 2) {
04168 sSend(":%s NOTICE %s :You must specify a channel.", ChanServ,
04169 from);
04170 return RET_SYNTAX;
04171 }
04172
04173 chan = getRegChanData(args[1]);
04174
04175 if (chan == NULL) {
04176 sSend(":%s NOTICE %s :The channel is not registered", ChanServ,
04177 from);
04178 return RET_NOTARGET;
04179 }
04180
04181 if (!opFlagged(nick, OVERRIDE | ODMOD)
04182 && (MFOUNDER > getChanOp(chan, from))) {
04183 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
04184 return RET_NOPERM;
04185 }
04186
04187 for (curr_akick = chan->firstAkick; curr_akick != (cAkickList *) NULL;
04188 curr_akick = next_akick) {
04189 next_akick = curr_akick->next;
04190 delChanAkick(chan, curr_akick);
04191 }
04192
04193 sendToChanOps(getChanData(chan->name), "%s wiped the akick list.",
04194 from);
04195 sSend(":%s NOTICE %s :All Akicks removed.", ChanServ, from);
04196 return RET_OK_DB;
04197 }
04198
04199
04204 CCMD(cs_wipeop)
04205 {
04206 char *from = nick->nick;
04207 RegChanList *chan;
04208 cAccessList *curr_op;
04209 cAccessList *next_op;
04210
04211
04212 if (numargs < 2) {
04213 sSend(":%s NOTICE %s :You must specify a channel.", ChanServ,
04214 from);
04215 return RET_SYNTAX;
04216 }
04217
04218 chan = getRegChanData(args[1]);
04219
04220 if (!opFlagged(nick, OVERRIDE | ODMOD)) {
04221 sSend(":%s NOTICE %s :Permission Denied -- this command is only available through DMOD and when using override mode.", ChanServ, from);
04222 return RET_NOPERM;
04223 }
04224
04225 if (chan == NULL) {
04226 sSend(":%s NOTICE %s :The channel is not registered", ChanServ,
04227 from);
04228 return RET_NOTARGET;
04229 }
04230
04231 for (curr_op = chan->firstOp; curr_op != (cAccessList *) NULL;
04232 curr_op = next_op) {
04233 next_op = curr_op->next;
04234 delChanOp(chan, curr_op);
04235 }
04236
04237 sSend(":%s NOTICE %s :All chanops removed.", ChanServ, from);
04238 return RET_OK_DB;
04239 }
04240
04245 CCMD(cs_delak)
04246 {
04247 char *from = nick->nick;
04248 RegChanList *chan;
04249 cAkickList *delak;
04250 int x;
04251
04252 if (numargs < 3) {
04253 sSend
04254 (":%s NOTICE %s :You must specify a channel and the AKick to delete",
04255 ChanServ, from);
04256 return RET_SYNTAX;
04257 }
04258
04259 chan = getRegChanData(args[1]);
04260
04261 if (chan == NULL) {
04262 sSend(":%s NOTICE %s :The channel is not registered", ChanServ,
04263 from);
04264 return RET_NOTARGET;
04265 }
04266
04267 if ((x = atoi(args[2]))) {
04268 for (delak = chan->firstAkick; delak; delak = delak->next) {
04269 if (delak->index == x)
04270 break;
04271 }
04272 } else
04273 delak = getChanAkick(chan, args[2]);
04274
04275 if (delak == NULL) {
04276 sSend(":%s NOTICE %s :%s is not in the akick list for %s",
04277 ChanServ, from, args[2], chan->name);
04278 return RET_NOTARGET;
04279 }
04280
04281 if (MSOP > getChanOp(chan, from) && !opFlagged(nick, OVERRIDE | ODMOD)) {
04282 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
04283 return RET_NOPERM;
04284 }
04285
04286 sendToChanOps(getChanData(chan->name), "%s deleted akick %s", from,
04287 delak->mask);
04288 sSend(":%s NOTICE %s :Removed AKick %s on %s", ChanServ, from,
04289 delak->mask, chan->name);
04290 delChanAkick(chan, delak);
04291 return RET_OK_DB;
04292 }
04293
04294
04295
04300 CCMD(cs_listop)
04301 {
04302 char *from = nick->nick;
04303 int levelsearch = 0;
04304 char namesearch[NICKLEN];
04305
04306 RegChanList *tmpchan;
04307
04308 bzero(namesearch, NICKLEN);
04309
04310 if (numargs == 1) {
04311 sSend(":%s NOTICE %s :You must specify a channel", ChanServ, from);
04312 return RET_SYNTAX;
04313 }
04314
04315 if (numargs == 2) {
04316 levelsearch = -1;
04317 namesearch[0] = 0;
04318 }
04319 if (numargs == 3) {
04320 sSend(":%s NOTICE %s :Improper command format", ChanServ, from);
04321 return RET_SYNTAX;
04322 }
04323 if (numargs == 4) {
04324 if (!strcasecmp(args[2], "-l"))
04325 levelsearch = atoi(args[3]);
04326 else if (!strcasecmp(args[2], "-n"))
04327 strncpyzt(namesearch, args[3], NICKLEN);
04328 else {
04329 sSend(":%s NOTICE %s :Unknown search parameter", ChanServ,
04330 from);
04331 return RET_SYNTAX;
04332 }
04333 }
04334
04335 tmpchan = getRegChanData(args[1]);
04336
04337 if ((tmpchan == NULL)) {
04338 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
04339 args[1]);
04340 return RET_NOTARGET;
04341 }
04342
04343 if ((getChanOp(tmpchan, from) < 1) && !isOper(nick)) {
04344 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
04345 return RET_NOPERM;
04346 }
04347
04348 return do_chanop_list(nick, tmpchan, namesearch[0] ? namesearch : NULL,
04349 levelsearch);
04350 }
04351
04352
04353
04358 CCMD(cs_listak)
04359 {
04360 char *from = nick->nick;
04361 char aktime[35];
04362 RegChanList *tmpchan;
04363 int i = 0, x = 0;
04364 char namesearch[NICKLEN + USERLEN + HOSTLEN + 5];
04365 cAkickList *tmp;
04366
04367 bzero(namesearch, NICKLEN + USERLEN + HOSTLEN);
04368 aktime[0] = '\0';
04369
04370 if (numargs == 1) {
04371 sSend(":%s NOTICE %s :You must specify a channel", ChanServ, from);
04372 return RET_SYNTAX;
04373 }
04374
04375 if (numargs == 2)
04376 namesearch[0] = 0;
04377
04378 if (numargs == 3) {
04379 sSend(":%s NOTICE %s :Improper command format", ChanServ, from);
04380 return RET_SYNTAX;
04381 }
04382
04383 if (numargs == 4) {
04384 if (!strcasecmp(args[2], "-n")) {
04385 strncpyzt(namesearch, args[3], NICKLEN + USERLEN + HOSTLEN);
04386 namesearch[sizeof(namesearch) - 1] = '\0';
04387 } else {
04388 sSend(":%s NOTICE %s :Unknown search parameter", ChanServ,
04389 from);
04390 return RET_SYNTAX;
04391 }
04392 }
04393
04394 tmpchan = getRegChanData(args[1]);
04395
04396 if (tmpchan == NULL) {
04397 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
04398 args[1]);
04399 return RET_NOTARGET;
04400 }
04401
04402 if ((getChanOp(tmpchan, from) < MAOP) && !isOper(nick)) {
04403 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
04404 return RET_NOPERM;
04405 }
04406
04407 sSend(":%s NOTICE %s :Akick Listing For %s", ChanServ, from, args[1]);
04408 sSend(":%s NOTICE %s :(Index) (Mask)", ChanServ, from);
04409 sSend(":%s NOTICE %s :(Time [GMT]) (Reason)", ChanServ, from);
04410
04411 for (tmp = tmpchan->firstAkick; tmp; tmp = tmp->next, i++) {
04412 if (namesearch[0]) {
04413 if (!match(namesearch, tmp->mask)) {
04414 strftime(aktime, sizeof(aktime), "%a %Y-%b-%d %T",
04415 gmtime(&tmp->added));
04416 aktime[sizeof(aktime) - 1] = '\0';
04417 sSend(":%s NOTICE %s :(%-3i) (%-s)", ChanServ, from,
04418 tmp->index, tmp->mask);
04419 sSend(":%s NOTICE %s :(%-20s) (%-s)", ChanServ, from,
04420 aktime, tmp->reason);
04421 x++;
04422 if ((x >= 15) && !isOper(nick) && (x % 3) == 0) {
04423 if (nick->floodlevel.GetLev() >= 66) {
04424 sSend(":%s NOTICE %s :Command cancelled (flood protection).", ChanServ, nick->nick);
04425 sSend(":%s NOTICE %s :Please wait at least 30 seconds before sending services further commands.", ChanServ, nick->nick);
04426 return RET_FAIL;
04427 }
04428 if (addFlood(nick, 1))
04429 return RET_FAIL;
04430 }
04431 }
04432 } else {
04433 strftime(aktime, sizeof(aktime), "%a %Y-%b-%d %T",
04434 gmtime(&tmp->added));
04435 aktime[sizeof(aktime) - 1] = '\0';
04436 sSend(":%s NOTICE %s :(%-3i) (%-s)", ChanServ, from,
04437 tmp->index, tmp->mask);
04438 sSend(":%s NOTICE %s :(%-20s) (%-s)", ChanServ, from, aktime,
04439 tmp->reason);
04440 x++;
04441 if ((x >= 15) && !isOper(nick) && (x % 3) == 0) {
04442 if (nick->floodlevel.GetLev() >= 66) {
04443 sSend(":%s NOTICE %s :Command cancelled (flood protection).", ChanServ, nick->nick);
04444 sSend(":%s NOTICE %s :Please wait at least 30 seconds before sending services further commands.", ChanServ, nick->nick);
04445 return RET_FAIL;
04446 }
04447 if (addFlood(nick, 1))
04448 return RET_FAIL;
04449 }
04450 }
04451 }
04452
04453 sSend(":%s NOTICE %s :%i akick elements searched", ChanServ, from, i);
04454 sSend(":%s NOTICE %s :%i matched given conditions", ChanServ, from, x);
04455 return RET_OK;
04456 }
04457
04458
04459
04464 CCMD(cs_drop)
04465 {
04466 RegChanList *tmp;
04467 ChanList *chan;
04468 char *from = nick->nick;
04469
04470 if (numargs < 3) {
04471 sSend(":%s NOTICE %s :You must specify a channel and password",
04472 ChanServ, from);
04473 return RET_SYNTAX;
04474 }
04475
04476 tmp = getRegChanData(args[1]);
04477
04478 if (tmp == NULL) {
04479 sSend(":%s NOTICE %s :The channel is not registered", ChanServ,
04480 from);
04481 return RET_NOTARGET;
04482 }
04483
04484 if ((tmp->flags & (CBANISH | CCLOSE)) && !isRoot(nick)) {
04485 sSend(":%s NOTICE %s :You cannot drop that channel because it is closed or banished.",
04486 ChanServ, from);
04487 return RET_EFAULT;
04488 }
04489
04490 if (isFounder(tmp, nick) == 0) {
04491 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
04492 return RET_NOPERM;
04493 }
04494
04495 if (!Valid_pw(args[2], tmp->password, ChanGetEnc(tmp))) {
04496 sSend(":%s NOTICE %s :Incorrect password, this has been logged",
04497 ChanServ, from);
04498 chanlog->log(nick, CS_DROP, args[1], LOGF_BADPW);
04499
04500 if (BadPwChan(nick, tmp))
04501 return RET_KILLED;
04502
04503 return RET_BADPW;
04504 }
04505
04506 if ((chan = getChanData(tmp->name)))
04507 sendToChanOps(chan, "%s just dropped %s", from, args[1]);
04508 sSend
04509 (":%s NOTICE %s :Channel registration for %s has been discontinued",
04510 ChanServ, from, args[1]);
04511 chan = getChanData(args[1]);
04512 if (chan)
04513 chan->reg = NULL;
04514 chanlog->log(nick, CS_DROP, args[1], 0);
04515
04516 GoodPwChan(nick, tmp);
04517 delRegChan(tmp);
04518 return RET_OK_DB;
04519 }
04520
04521
04522
04528 CCMD(cs_op)
04529 {
04530 char *from = nick->nick;
04531 int a, mylevel;
04532 RegChanList *tmp;
04533 ChanList *chan;
04534 cNickList *tmpnick;
04535
04536 if (numargs < 2) {
04537 sSend(":%s NOTICE %s :You must specify a channel", ChanServ, from);
04538 return RET_SYNTAX;
04539 }
04540
04541 tmp = getRegChanData(args[1]);
04542 chan = getChanData(args[1]);
04543 if (chan == NULL) {
04544 sSend(":%s NOTICE %s :%s: No such channel", ChanServ, from,
04545 args[1]);
04546 return RET_NOTARGET;
04547 }
04548 if (tmp == NULL) {
04549 sSend
04550 (":%s NOTICE %s :Cannot receive ops on non registered channel",
04551 ChanServ, from);
04552 return RET_FAIL;
04553 }
04554
04555 if (numargs == 3)
04556 tmpnick = getChanUserData(chan, getNickData(args[2]));
04557 else
04558 tmpnick = getChanUserData(chan, nick);
04559
04560 if (tmpnick == NULL) {
04561 sSend(":%s NOTICE %s :%s is not in %s", ChanServ, from,
04562 (numargs == 3) ? args[2] : from, args[1]);
04563 return RET_FAIL;
04564 }
04565
04566 a = getChanOp(tmp, (numargs == 3) ? args[2] : from);
04567
04568 if (a == 0 || ((mylevel = getChanOp(tmp, from)) < MAOP)) {
04569 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
04570 return RET_NOPERM;
04571 }
04572
04573 if ((mylevel < MFOUNDER) && (mylevel <= AOP) && (mylevel < a)) {
04574 sSend
04575 (":%s NOTICE %s :Permission denied -- a(n) %s cannot use this command on a(n) %s.",
04576 ChanServ, from, opLevelName(mylevel, 0), opLevelName(a, 0));
04577 return RET_NOPERM;
04578 }
04579
04580 if (getChanData(tmp->name)
04581 && strcmp(from, (numargs == 3) ? args[2] : from)) {
04582 if (mylevel < AOP) {
04583 sSend(":%s NOTICE %s :Access Denied", ChanServ, from);
04584 return RET_NOPERM;
04585 }
04586 sendToChanOpsAlways(getChanData(tmp->name),
04587 "%s used \002OP\002 on %s", from,
04588 (numargs == 3) ? args[2] : from);
04589 }
04590
04591 if (mylevel < AOP || a < AOP) {
04592 sSend(":%s MODE %s +v %s", ChanServ, args[1],
04593 (numargs == 3) ? args[2] : from);
04594 tmpnick->op |= CHANVOICE;
04595 tmp->timestamp = CTime;
04596
04597
04598 if (tmp && tmp->name && !strcasecmp(tmp->name, HELPOPS_CHAN)
04599 && (getChanOp(tmp, nick->nick) >= 4) && (numargs < 3)) {
04600 sSend(":ChanServ MODE %s :+h", from);
04601 nick->oflags |= NISHELPOP;
04602 }
04603
04604 return RET_OK;
04605 } else {
04606 sSend(":%s MODE %s +o %s", ChanServ, args[1],
04607 (numargs == 3) ? args[2] : from);
04608 tmpnick->op |= CHANOP;
04609 tmp->timestamp = CTime;
04610
04611 if (tmp && tmp->name && tmp && !strcasecmp(tmp->name, HELPOPS_CHAN)
04612 && !strcasecmp(from, (numargs >= 3) ? args[2] : from)
04613 && (getChanOp(tmp, nick->nick) >= 4) && (numargs < 3)) {
04614 sSend(":ChanServ MODE %s :+h", from);
04615 nick->oflags |= NISHELPOP;
04616 }
04617
04618 return RET_OK;
04619 }
04620 return RET_OK;
04621 }
04622
04623
04624
04629 CCMD(cs_deop)
04630 {
04631 char *from = nick->nick;
04632 UserList *target;
04633 ChanList *chan;
04634 cNickList *deopto;
04635 int mylevel, victlevel, self_deop = 0;
04636
04637 if (numargs < 3) {
04638 sSend(":%s NOTICE %s :You must specify a channel and user to deop",
04639 ChanServ, from);
04640 return RET_SYNTAX;
04641 }
04642
04643 chan = getChanData(args[1]);
04644
04645 if (chan == NULL) {
04646 sSend(":%s NOTICE %s :%s: No such channel", ChanServ, from,
04647 args[1]);
04648 return RET_NOTARGET;
04649 }
04650
04651 if (chan->reg == NULL) {
04652 sSend(":%s NOTICE %s :%s: Is not registered", ChanServ, from,
04653 args[1]);
04654 return RET_NOTARGET;
04655 }
04656
04657 deopto = getChanUserData(chan, getNickData(args[2]));
04658 target = getNickData((numargs >= 3) ? args[2] : from);
04659
04660 if (deopto == NULL) {
04661 sSend(":%s NOTICE %s :%s is not in %s", ChanServ, from, args[2],
04662 args[1]);
04663 return RET_NOTARGET;
04664 }
04665
04666 if ((mylevel = getChanOp(chan->reg, from)) < MAOP) {
04667 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
04668 return RET_NOPERM;
04669 }
04670
04671 victlevel = getChanOp(chan->reg, args[2]);
04672
04673 if (!strcmp(from, (numargs == 3) ? args[2] : from))
04674 self_deop = 1;
04675
04676 if ((victlevel > mylevel) || ((mylevel <= MAOP) && !self_deop)) {
04677 sSend
04678 (":%s NOTICE %s :Permission denied -- a level %d operator may not deop another level %d operator.",
04679 ChanServ, from, mylevel, victlevel);
04680 return RET_NOPERM;
04681 }
04682
04683 if (chan && chan->reg && target && (target->oflags & NISHELPOP)
04684 && !(target->oflags & NISOPER) && chan->name
04685 && !strcasecmp(chan->name, HELPOPS_CHAN)
04686 && (getChanOp(chan->reg, target->nick) <= 5)) {
04687 sSend(":ChanServ MODE %s :-h", target->nick);
04688 target->oflags &= ~NISHELPOP;
04689 }
04690
04691 sendToChanOpsAlways(getChanData(chan->reg->name),
04692 "%s used \002DEOP\002 on %s", from, args[2]);
04693 sSend(":%s MODE %s -ov %s %s", ChanServ, args[1], args[2], args[2]);
04694 deopto->op &= ~CHANOP;
04695 return RET_OK;
04696 }
04697
04698
04699
04707 CCMD(cs_banish)
04708 {
04709 char *from = nick->nick;
04710 ChanList *ochan;
04711 RegChanList *chan;
04712
04713 if (!isServop(nick) && !opFlagged(nick, OOPER | OCBANDEL)) {
04714 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
04715 return RET_NOPERM;
04716 }
04717
04718 if (numargs < 2) {
04719 sSend(":%s NOTICE %s :Must supply at least one argument", ChanServ,
04720 from);
04721 return RET_SYNTAX;
04722 }
04723
04724 if (!isRoot(nick) && is_sn_chan(args[1])) {
04725 sSend(":%s NOTICE %s :That channel cannot be banished (magic channel).", ChanServ,
04726 from);
04727 return RET_EFAULT;
04728 }
04729
04730 chan = getRegChanData(args[1]);
04731 if ((*args[1] != '#' && *args[1] != '+')) {
04732 sSend(":%s NOTICE %s :Invalid channel name.", ChanServ, from);
04733 return RET_EFAULT;
04734 }
04735
04736 if (numargs < 3) {
04737 ochan = getChanData(args[1]);
04738 if (!chan) {
04739 chan = (RegChanList *) oalloc(sizeof(RegChanList));
04740 initRegChanData(chan);
04741
04742 strncpyzt(chan->name, args[1], CHANLEN);
04743
04744 addRegChan(chan);
04745 mostchans++;
04746 if (ochan)
04747 ochan->reg = chan;
04748 chan->founderId = RegId(0, 1);
04749 chan->password[0] = '\0';
04750
04751
04752 chan->timereg = chan->timestamp = CTime;
04753 chan->flags |= CBANISH|CENCRYPT;
04754 chan->mlock = (PM_N | PM_T | MM_K);
04755 }
04756 chan->flags |= CBANISH;
04757
04758 sSend(":%s NOTICE %s :%s is now \2BANISHED\2.", ChanServ, from,
04759 args[1]);
04760 sSend(":%s GLOBOPS :%s set banish on %s.", ChanServ, from,
04761 args[1]);
04762 chanlog->log(nick, CS_BANISH, chan->name);
04763 return RET_OK_DB;
04764 }
04765
04766 if (!strcasecmp(args[2], "on") || !strcasecmp(args[2], "yes")
04767 || !strcasecmp(args[2], "banish")) {
04768 sSend(":%s NOTICE %s :%s is now \2BANISHED\2.", ChanServ, from,
04769 args[1]);
04770 sSend(":%s GLOBOPS :%s set banish on %s.", ChanServ, from,
04771 args[1]);
04772 chan->flags |= CBANISH;
04773 chanlog->log(nick, CS_BANISH, chan->name, LOGF_ON);
04774 return RET_OK_DB;
04775 } else if (!strcasecmp(args[2], "off") || !strcasecmp(args[2], "no")) {
04776 sSend(":%s NOTICE %s :%s is now \2not banished\2.", ChanServ, from,
04777 args[1]);
04778 chan->flags &= ~CBANISH;
04779 chanlog->log(nick, CS_BANISH, chan->name, LOGF_OFF);
04780 return RET_OK_DB;
04781 } else {
04782 sSend(":%s NOTICE %s :Unrecognized usage.", ChanServ, from);
04783 sSend(":%s NOTICE %s :BANISH <#channel> [<on|off>]", ChanServ,
04784 from);
04785 return RET_SYNTAX;
04786 }
04787 return RET_OK;
04788 }
04789
04790
04791
04792
04801 CCMD(cs_close)
04802 {
04803 char *from = nick->nick;
04804 RegChanList *chan;
04805
04806 if (!isServop(nick) && !opFlagged(nick, OOPER | OCBANDEL)) {
04807 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
04808 return RET_NOPERM;
04809 }
04810
04811 if (numargs < 2) {
04812 sSend(":%s NOTICE %s :Must supply at least one argument", ChanServ,
04813 from);
04814 return RET_SYNTAX;
04815 }
04816
04817 chan = getRegChanData(args[1]);
04818 if (chan == NULL) {
04819 sSend(":%s NOTICE %s :Channel not found", ChanServ, from);
04820 return RET_NOTARGET;
04821 }
04822
04823 if (numargs < 3) {
04824 sSend(":%s NOTICE %s :%s is \2%s\2.", ChanServ, from, args[1],
04825 chan->flags & CHOLD ? "Closed" : "Not closed");
04826 return RET_OK;
04827 }
04828
04829 if (!strcasecmp(args[2], "on") || !strcasecmp(args[2], "yes")
04830 || !strcasecmp(args[2], "close")) {
04831 sSend(":%s NOTICE %s :%s is now \2CLOSED\2.", ChanServ, from,
04832 args[1]);
04833 sSend(":%s GLOBOPS :%s closed channel %s.", ChanServ, from,
04834 args[1]);
04835 chan->flags |= CCLOSE;
04836 chanlog->log(nick, CS_CLOSE, chan->name, LOGF_ON);
04837
04838 return RET_OK_DB;
04839 } else if (!strcasecmp(args[2], "off") || !strcasecmp(args[2], "no")) {
04840 sSend(":%s NOTICE %s :%s is now \2OPEN\2.", ChanServ, from,
04841 args[1]);
04842 chan->flags &= ~CCLOSE;
04843 chanlog->log(nick, CS_CLOSE, chan->name, LOGF_OFF);
04844
04845 return RET_OK_DB;
04846 } else {
04847 sSend(":%s NOTICE %s :Unrecognized usage.", ChanServ, from);
04848 sSend(":%s NOTICE %s :CLOSE <#channel> [<on|off>]", ChanServ,
04849 from);
04850 return RET_OK_DB;
04851 }
04852 }
04853
04854
04855
04864 CCMD(cs_hold)
04865 {
04866 char *from = nick->nick;
04867 RegChanList *chan;
04868
04869 if (!isRoot(nick)) {
04870 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
04871 return RET_NOPERM;
04872 }
04873
04874 if (numargs < 2) {
04875 sSend(":%s NOTICE %s :Must supply at least one argument", ChanServ,
04876 from);
04877 return RET_SYNTAX;
04878 }
04879
04880 chan = getRegChanData(args[1]);
04881 if (chan == NULL) {
04882 sSend(":%s NOTICE %s :Channel not found", ChanServ, from);
04883 return RET_NOTARGET;
04884 }
04885 if (numargs < 3) {
04886 sSend(":%s NOTICE %s :%s is \2%s\2.", ChanServ, from, args[1],
04887 chan->flags & CHOLD ? "Held" : "Not Held");
04888 return RET_OK;
04889 }
04890 if (!strcasecmp(args[2], "on") || !strcasecmp(args[2], "yes")) {
04891 sSend(":%s NOTICE %s :%s is now \2Held\2.", ChanServ, from,
04892 args[1]);
04893 chan->flags |= CHOLD;
04894 chanlog->log(nick, CS_HOLD, chan->name, LOGF_ON);
04895 return RET_OK_DB;
04896 } else if (!strcasecmp(args[2], "off") || !strcasecmp(args[2], "no")) {
04897 sSend(":%s NOTICE %s :%s is now \2Held\2.", ChanServ, from,
04898 args[1]);
04899 chan->flags &= ~CHOLD;
04900 chanlog->log(nick, CS_HOLD, chan->name, LOGF_OFF);
04901 return RET_OK_DB;
04902 } else {
04903 sSend(":%s NOTICE %s :Unrecognized usage.", ChanServ, from);
04904 sSend(":%s NOTICE %s :HOLD <#channel> <on|off>", ChanServ, from);
04905 return RET_SYNTAX;
04906 }
04907 return RET_OK;
04908 }
04909
04910
04911
04934 CCMD(cs_mark)
04935 {
04936 char *from = nick->nick;
04937 RegChanList *chan;
04938
04939 if (!isServop(nick)) {
04940 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
04941 return RET_NOPERM;
04942 }
04943
04944 if (numargs < 2) {
04945 sSend(":%s NOTICE %s :Must supply at least one argument", ChanServ,
04946 from);
04947 return RET_SYNTAX;
04948 }
04949
04950 chan = getRegChanData(args[1]);
04951 if (chan == NULL) {
04952 sSend(":%s NOTICE %s :Channel not found", ChanServ, from);
04953 return RET_NOTARGET;
04954 }
04955 if (numargs < 3) {
04956 sSend(":%s NOTICE %s :%s is \2%s\2.", ChanServ, from, args[1],
04957 chan->flags & CMARK ? "Marked" : "Not Marked");
04958 return RET_OK;
04959 }
04960 if (!strcasecmp(args[2], "on") || !strcasecmp(args[2], "yes")) {
04961 if (chan->flags & CMARK) {
04962 if (chan->markby)
04963 sSend(":%s NOTICE %s :%s has already been marked by %s.",
04964 ChanServ, from, args[1], chan->markby);
04965 else
04966 sSend(":%s NOTICE %s :%s has already been marked.",
04967 ChanServ, from, args[1]);
04968 return RET_OK;
04969 }
04970 sSend(":%s NOTICE %s :%s is now \2Marked\2.", ChanServ, from,
04971 args[1]);
04972 chan->flags |= CMARK;
04973 if (chan->markby)
04974 FREE(chan->markby);
04975 chan->markby = strdup(nick->nick);
04976 chanlog->log(nick, CS_MARK, chan->name, LOGF_ON);
04977 return RET_OK_DB;
04978 } else if (!strcasecmp(args[2], "off") || !strcasecmp(args[2], "no")) {
04979 sSend(":%s NOTICE %s :%s is now \2Unmarked\2.", ChanServ, from,
04980 args[1]);
04981 chan->flags &= ~CMARK;
04982 chanlog->log(nick, CS_MARK, chan->name, LOGF_OFF);
04983 if (chan->markby)
04984 FREE(chan->markby);
04985 chan->markby = NULL;
04986 return RET_OK_DB;
04987 } else {
04988 sSend(":%s NOTICE %s :Unrecognized usage.", ChanServ, from);
04989 sSend(":%s NOTICE %s :MARK <#channel> <on|off>", ChanServ, from);
04990 return RET_SYNTAX;
04991 }
04992 return RET_OK;
04993 }
04994
04995
04996
05003 CCMD(cs_clist)
05004 {
05005 char *from = nick->nick;
05006 char tmpch[IRCBUF] = "";
05007 ChanList *chan;
05008 cNickList *tmp;
05009 UserList *tnick;
05010 int c;
05011
05012 if (numargs < 2) {
05013 sSend(":%s NOTICE %s :Must specify a channel name.", ChanServ,
05014 from);
05015 return RET_SYNTAX;
05016 }
05017
05018 chan = getChanData(args[1]);
05019
05020 if (!opFlagged(nick, OOPER) && (!chan || !chan->reg || (getChanOpId(chan->reg, from) < SOP))) {
05021 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
05022 return RET_NOPERM;
05023 }
05024
05025 tnick = getNickData(args[1]);
05026
05027 if (chan == NULL) {
05028 if (!tnick || !isRoot(nick)) {
05029 sSend(":%s NOTICE %s :Channel not found", ChanServ, from);
05030 return RET_NOTARGET;
05031 }
05032
05033
05034 else {
05035 cNickList *cu;
05036 int i;
05037
05038
05039 sSend(":%s NOTICE %s :*** %s [%s@%s]", ChanServ, from,
05040 tnick->nick, tnick->user, tnick->host);
05041 sSend(":%s NOTICE %s :ID: %ld, TS: %ld, LT: %ld", ChanServ,
05042 from, tnick->idnum.getHashKey(), tnick->timestamp, tnick->floodlevel.GetLev());
05043 sSend(":%s NOTICE %s :OF: %d, FL: %d, CA: %d", ChanServ, from,
05044 tnick->oflags, tnick->floodlevel.GetLev(), tnick->caccess);
05045
05046 for (i = 0; i < NICKCHANHASHSIZE; i++) {
05047 if (tnick->chan[i]) {
05048 if ((cu = getChanUserData(tnick->chan[i], tnick))) {
05049 if ((cu->op & CHANVOICE))
05050 strcat(tmpch, "+");
05051 if ((cu->op & CHANOP))
05052 strcat(tmpch, "@");
05053 }
05054 strncat(tmpch, tnick->chan[i]->name, CHANLEN);
05055 strcat(tmpch, " ");
05056 if (strlen(tmpch) > 80) {
05057 sSend(":%s NOTICE %s :%s", ChanServ, from, tmpch);
05058 tmpch[0] = '\0';
05059 }
05060 }
05061 }
05062 if (*tmpch != '\0')
05063 sSend(":%s NOTICE %s :%s", ChanServ, from, tmpch);
05064 return RET_OK;
05065 }
05066 }
05067
05068
05069 if (!opFlagged(nick, OVERRIDE | OROOT))
05070 if (chan->modes & (PM_S | PM_I)) {
05071 for (tmp = chan->firstUser; tmp; tmp = tmp->next)
05072 if (tmp->person == nick)
05073 break;
05074 if (!tmp) {
05075 if (!opFlagged(nick, OROOT))
05076 sSend(":%s NOTICE %s :Channel not found", ChanServ,
05077 from);
05078 else {
05079 sSend
05080 (":%s NOTICE %s :That channel is secret (+s) or private (+p)",
05081 ChanServ, from);
05082 sSend
05083 (":%s NOTICE %s :Use the %s OVERRIDE command to override.",
05084 ChanServ, from, OperServ);
05085 }
05086 return RET_FAIL;
05087 }
05088 }
05089
05090
05091
05092
05093
05094
05095
05096 tmpch[0] = '\0';
05097 c = 0;
05098
05099 sSend(":%s NOTICE %s :Channel membership for \2%s\2:", ChanServ, from, chan->name);
05100 for (tmp = chan->firstUser; tmp; tmp = tmp->next) {
05101 c += sprintf(tmpch+c, "%.1s%.1s%.1s%-18.30s",
05102 *tmpch ? " " : "",
05103 tmp->op & CHANVOICE ? "+" : "",
05104 tmp->op & CHANOP ? "@" : "",
05105 tmp->person->nick);
05106 if (c >= 80) {
05107 sSend(":%s NOTICE %s :%s", ChanServ, from, tmpch);
05108 c = 0;
05109 tmpch[0] = '\0';
05110 }
05111 }
05112
05113 if (tmpch[0] != '\0')
05114 sSend(":%s NOTICE %s :%s", ChanServ, from, tmpch);
05115 sSend(":%s NOTICE %s :End of channel member list.", ChanServ, from);
05116 return RET_OK;
05117 }
05118
05119
05120
05126 CCMD(cs_whois)
05127 {
05128 char *from = nick->nick;
05129 UserList *tnick;
05130 char tmpch[(CHANLEN + 4) * NICKCHANHASHSIZE] = "";
05131 cNickList *c;
05132 int i;
05133
05134 if (!opFlagged(nick, OOPER | OSERVOP)) {
05135 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
05136 return RET_NOPERM;
05137 }
05138
05139 if (numargs != 2) {
05140 sSend(":%s NOTICE %s :Must supply at least one argument", ChanServ,
05141 from);
05142 return RET_SYNTAX;
05143 }
05144
05145 tnick = getNickData(args[1]);
05146
05147 if (!tnick) {
05148 sSend(":%s NOTICE %s :Nick not found", ChanServ, from);
05149 return RET_NOTARGET;
05150 }
05151
05152 sSend(":%s GLOBOPS :%s uses CWHOIS on %s", ChanServ, from, args[1]);
05153 operlog->log(nick, CS_WHOIS, fullhost1(tnick));
05154
05155 sSend(":%s NOTICE %s :*** %s [%s@%s]", ChanServ, from, tnick->nick,
05156 tnick->user, tnick->host);
05157 for (i = 0; i < NICKCHANHASHSIZE; i++) {
05158 if (tnick->chan[i]) {
05159 if ((c = getChanUserData(tnick->chan[i], tnick))) {
05160 if ((c->op & CHANVOICE))
05161 strcat(tmpch, "+");
05162 if ((c->op & CHANOP))
05163 strcat(tmpch, "@");
05164 }
05165 strncat(tmpch, tnick->chan[i]->name, CHANLEN);
05166 strcat(tmpch, " ");
05167 if (strlen(tmpch) > 80) {
05168 sSend(":%s NOTICE %s :%s", ChanServ, from, tmpch);
05169 tmpch[0] = '\0';
05170 }
05171 }
05172 }
05173 if (tmpch[0])
05174 sSend(":%s NOTICE %s :%s", ChanServ, from, tmpch);
05175 return RET_OK;
05176 }
05177
05178
05179
05184 CCMD(cs_restrict)
05185 {
05186 char *from = nick->nick;
05187 RegChanList *regchan;
05188
05189 if (numargs < 2) {
05190 sSend(":%s NOTICE %s :Too few arguments to RESTRICT command",
05191 ChanServ, from);
05192 return RET_SYNTAX;
05193 }
05194
05195 regchan = getRegChanData(args[1]);
05196
05197 if (!regchan) {
05198 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
05199 args[1]);
05200 return RET_NOTARGET;
05201 }
05202
05203 return cs_set_restrict(NULL, nick, regchan, args, numargs);
05204 }
05205
05206
05207
05212 CCMD(cs_topiclock)
05213 {
05214 char *from = nick->nick;
05215 RegChanList *regchan;
05216
05217 if (numargs < 2) {
05218 sSend(":%s NOTICE %s :Too few arguments to TOPICLOCK command",
05219 ChanServ, from);
05220 return RET_SYNTAX;
05221 }
05222
05223 regchan = getRegChanData(args[1]);
05224
05225 if (!regchan) {
05226 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
05227 args[1]);
05228 return RET_NOTARGET;
05229 }
05230
05231 return cs_set_topiclock(NULL, nick, regchan, args, numargs);
05232 }
05233
05234
05235
05240 CCMD(cs_modelock)
05241 {
05242 char *from = nick->nick;
05243 RegChanList *regchan;
05244
05245 if (numargs < 3) {
05246 sSend(":%s NOTICE %s :Too few arguments to MODELOCK command",
05247 ChanServ, from);
05248 sSend
05249 (":%s NOTICE %s :For usage information, type \2/CHANSERV HELP MLOCK\2",
05250 ChanServ, from);
05251 return RET_SYNTAX;
05252 }
05253
05254 regchan = getRegChanData(args[1]);
05255
05256 if (!regchan) {
05257 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
05258 args[1]);
05259 return RET_NOTARGET;
05260 }
05261
05262 if (MFOUNDER > getChanOpId(regchan, from)) {
05263 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
05264 return RET_NOPERM;
05265 }
05266
05267 return cs_set_mlock(NULL, nick, regchan, args, numargs);
05268 }
05269
05270
05271
05277 #define CSO(q) (((size_t) &((RegChanList *)0)->q))
05278
05284 CCMD(cs_set)
05285 {
05286 char *from = nick->nick;
05287 RegChanList *chan;
05288 ChanList *tmp;
05289 cs_settbl_t *cmd;
05290
05291 cs_settbl_t cs_setcmd[] = {
05292
05293 {"opguard", cs_set_bool, FOUNDER, CSO(flags), "op guard",
05294 COPGUARD},
05295 {"protop", cs_set_bool, FOUNDER, CSO(flags), "protop", CPROTOP},
05296 {"keeptopic", cs_set_bool, FOUNDER, CSO(flags), "topic holding",
05297 CKTOPIC},
05298 {"ident", cs_set_bool, FOUNDER, CSO(flags), "ident", CIDENT},
05299 {"quiet", cs_set_bool, FOUNDER + 1, CSO(flags), "quiet changes",
05300 CQUIET},
05301 {"passw*d", cs_set_passwd, FOUNDER + 1},
05302 {"memo*", cs_set_memolvl, FOUNDER},
05303 {"desc*", cs_set_fixed, FOUNDER, CSO(desc), "description",
05304 CHANDESCBUF},
05305 {"founder", cs_set_founder, 0, 0},
05306 {"autogreet", cs_set_string, FOUNDER, CSO(autogreet), NULL, 255},
05307 {"url", cs_set_string, FOUNDER, CSO(url), NULL, 255},
05308 {"mlock", cs_set_mlock, FOUNDER, 0},
05309 {"restrict", cs_set_restrict, MFOUNDER, 0},
05310 {"topiclock", cs_set_topiclock, MFOUNDER, 0},
05311 {"encrypt", cs_set_encrypt, 0, 0},
05312 {NULL}
05313 };
05314
05315 if (numargs < 2) {
05316 sSend
05317 (":%s NOTICE %s :You must specify arguments after the SET command",
05318 ChanServ, from);
05319 return RET_SYNTAX;
05320 }
05321
05322 chan = getRegChanData(args[1]);
05323 tmp = getChanData(args[1]);
05324
05325 if (chan == NULL) {
05326 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
05327 args[1]);
05328 return RET_NOTARGET;
05329 }
05330
05331 if (!isOper(nick) && (chan->flags & CFORCEXFER)) {
05332 sSend(":%s NOTICE %s :services for %s have been temporarily "
05333 "suspended.", ChanServ, from,
05334 args[1]);
05335 return RET_NOTARGET;
05336 }
05337
05338 if (tmp && (tmp->reg != chan)) {
05339 logDump(corelog,
05340 "WARNING! tmp->reg != getRegChanData(tmp->name) (%s) (%s)",
05341 tmp->name, chan->name);
05342 tmp->reg = chan;
05343 }
05344
05345 if (isOper(nick) && opFlagged(nick, ODMOD | OVERRIDE)) {
05346 sSend(":%s GLOBOPS :%s using directmod on %s with set '%s'",
05347 ChanServ, nick->nick, chan->name, args[2]);
05348 }
05349
05350 for (cmd = cs_setcmd; cmd->cmd != NULL; cmd++) {
05351 if (!match(cmd->cmd, args[2])) {
05352
05353
05354 if ((cmd->aclvl == (FOUNDER + 3))
05355 && !opFlagged(nick, OOPER | ODMOD | OVERRIDE)) {
05356 sSend(":%s NOTICE %s :Option not available.\r\n"
05357 ":%s NOTICE %s :Please try /msg %s HELP", ChanServ,
05358 from, ChanServ, from, ChanServ);
05359 return RET_NOPERM;
05360 } else if ((cmd->aclvl == (FOUNDER + 2)) && !isRoot(nick))
05361 continue;
05362 else if ((cmd->aclvl == (FOUNDER + 1))
05363 && !opFlagged(nick, OOPER | ODMOD | OVERRIDE)) {
05364 if (!isFounder(chan, nick)) {
05365 sSend
05366 (":%s NOTICE %s :You must identify as channel founder with the channel password to alter the value of that setting.",
05367 ChanServ, from);
05368 return RET_NOPERM;
05369 }
05370 } else if (!opFlagged(nick, OOPER | ODMOD | OVERRIDE)
05371 && (cmd->aclvl > getChanOpId(chan, from))) {
05372 sSend(":%s NOTICE %s :Access denied.", ChanServ, from);
05373 return RET_NOPERM;
05374 }
05375
05376 return cmd->func(cmd, nick, chan, args + 1, numargs - 1);
05377 }
05378 }
05379
05380 sSend(":%s NOTICE %s :Unknown SET item.\r\n"
05381 ":%s NOTICE %s :Please try /msg %s HELP", ChanServ, from,
05382 ChanServ, from, ChanServ);
05383 return RET_EFAULT;
05384 }
05385
05389 cmd_return cs_set_string(cs_settbl_t * cmd, UserList * nick,
05390 RegChanList * regchan, char **args, int numargs)
05391 {
05392 char *from = nick->nick, **str_target;
05393 char tmpbuf[IRCBUF + 1];
05394 int i;
05395
05396 if (!regchan)
05397 return RET_OK;
05398 str_target = (char **)(((regchan->name) + (cmd->xoff)));
05399 *tmpbuf = '\0';
05400
05401 if (numargs == 3 && !strcasecmp(args[2], "*")) {
05402 sSend(":%s NOTICE %s :The %s of %s is now unspecified.", ChanServ,
05403 from, cmd->optname ? cmd->optname : cmd->cmd, regchan->name);
05404 if (str_target)
05405 FREE((*str_target));
05406 (*str_target) = NULL;
05407 return RET_OK_DB;
05408 }
05409
05410 if (numargs >= 3) {
05411 for (i = 2; i < numargs; i++) {
05412 if (strlen(tmpbuf) + strlen(args[i]) >= cmd->optlen)
05413 break;
05414 strcat(tmpbuf, args[i]);
05415 if (i + 1 < numargs)
05416 strcat(tmpbuf, " ");
05417 }
05418
05419 if (i < numargs && !*tmpbuf) {
05420 sSend(":%s NOTICE %s :Text line too long (must be %lu or shorter).",
05421 ChanServ, from, cmd->optlen);
05422 return RET_EFAULT;
05423 }
05424
05425 if ((*str_target))
05426 FREE((*str_target));
05427 (*str_target) = NULL;
05428
05429 (*str_target) = (char *)oalloc(strlen(tmpbuf) + 1);
05430 strcpy((*str_target), tmpbuf);
05431 sSend(":%s NOTICE %s :The %s of %s is now: %s", ChanServ, from,
05432 cmd->optname ? cmd->optname : cmd->cmd, regchan->name,
05433 (*str_target));
05434 return RET_OK_DB;
05435 }
05436
05437 if (*str_target)
05438 sSend(":%s NOTICE %s :The %s of %s is: %s", ChanServ, from,
05439 cmd->optname ? cmd->optname : cmd->cmd, regchan->name,
05440 (*str_target));
05441 else
05442 sSend(":%s NOTICE %s :The %s of %s is empty.", ChanServ, from,
05443 cmd->optname ? cmd->optname : cmd->cmd, regchan->name);
05444 return RET_OK;
05445 }
05446
05450 cmd_return cs_set_fixed(cs_settbl_t * cmd, UserList * nick,
05451 RegChanList * regchan, char **args, int numargs)
05452 {
05453 char *from = nick->nick, *str_target;
05454 int i;
05455
05456 if (!regchan || !cmd->optlen)
05457 return RET_FAIL;
05458 str_target = (char *)((regchan->name) + (cmd->xoff));
05459
05460 if (numargs == 3 && !strcasecmp(args[2], "*") && (!cmd->optname || strcmp(cmd->optname, "description"))) {
05461 sSend(":%s NOTICE %s :The %s of %s is now unspecified.", ChanServ,
05462 from, cmd->optname ? cmd->optname : cmd->cmd, regchan->name);
05463 (*str_target) = '\0';
05464 return RET_OK_DB;
05465 }
05466
05467 if (numargs >= 3) {
05468 (*str_target) = '\0';
05469
05470 for (i = 2; i < numargs; i++) {
05471 if (strlen((str_target)) + strlen(args[i]) >= cmd->optlen)
05472 break;
05473 strcat((str_target), args[i]);
05474 if (i + 1 < numargs)
05475 strcat((str_target), " ");
05476 }
05477
05478 if (i < numargs && !*str_target)
05479 sSend(":%s NOTICE %s :Text line too long (must be %lu or shorter).",
05480 ChanServ, from, cmd->optlen);
05481 sSend(":%s NOTICE %s :The %s of %s is now: %s", ChanServ, from,
05482 cmd->optname ? cmd->optname : cmd->cmd, regchan->name,
05483 str_target);
05484 return RET_OK_DB;
05485 }
05486 sSend(":%s NOTICE %s :The %s of %s is: %s", ChanServ, from,
05487 cmd->optname ? cmd->optname : cmd->cmd, regchan->name,
05488 (str_target));
05489 return RET_OK;
05490 }
05491
05495 cmd_return cs_set_bool(cs_settbl_t * cmd, UserList * nick,
05496 RegChanList * regchan, char **args, int numargs)
05497 {
05498 long *long_target;
05499 char *from = nick->nick;
05500 ChanList *chan;
05501
05502 if (!regchan || !cmd->optlen)
05503 return RET_FAIL;
05504 long_target = (long *)(((regchan->name) + (cmd->xoff)));
05505 chan = getChanData(regchan->name);
05506
05507 if (numargs < 3) {
05508 sSend(":%s NOTICE %s :For %s, %s is currently %s.", ChanServ, from,
05509 regchan->name, cmd->optname ? cmd->optname : cmd->cmd,
05510 ((*long_target) & cmd->optlen) ? "ON" : "OFF");
05511 return RET_OK;
05512 }
05513
05514 if (!strcasecmp(args[2], "ON")) {
05515 (*long_target) |= cmd->optlen;
05516 sSend(":%s NOTICE %s :For %s, %s is now \2on\2.", ChanServ, from,
05517 regchan->name, cmd->optname ? cmd->optname : cmd->cmd);
05518 if (chan)
05519 sendToChanOps(chan, "%s set %s on.", from,
05520 cmd->optname ? cmd->optname : cmd->cmd);
05521 return RET_OK_DB;
05522 } else if (!strcasecmp(args[2], "OFF")) {
05523 (*long_target) &= ~cmd->optlen;
05524 sSend(":%s NOTICE %s :For %s, %s is now \2off\2.", ChanServ, from,
05525 regchan->name, cmd->optname ? cmd->optname : cmd->cmd);
05526 if (chan)
05527 sendToChanOps(chan, "%s set %s off.", from,
05528 cmd->optname ? cmd->optname : cmd->cmd);
05529 return RET_OK_DB;
05530 } else {
05531 sSend(":%s NOTICE %s :For %s, %s is currently %s.", ChanServ, from,
05532 regchan->name, cmd->optname ? cmd->optname : cmd->cmd,
05533 ((*long_target) & cmd->optlen) ? "ON" : "OFF");
05534 return RET_OK;
05535 }
05536 return RET_OK;
05537 }
05538
05542 cmd_return cs_set_restrict(cs_settbl_t * cmd, UserList * nick,
05543 RegChanList * regchan, char **args, int numargs)
05544 {
05545 char *from = nick->nick;
05546 ChanList *tmpchan;
05547 int reslevel;
05548
05549 if (regchan == NULL) {
05550 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
05551 args[1]);
05552 return RET_NOTARGET;
05553 }
05554
05555 tmpchan = getChanData(regchan->name);
05556
05557 if (numargs < 3) {
05558 if (regchan->restrictlevel)
05559 sSend
05560 (":%s NOTICE %s :Access to \2%s\2 currently restricted to %s.",
05561 ChanServ, from, regchan->name,
05562 opLevelName(regchan->restrictlevel, 2));
05563 else
05564 sSend
05565 (":%s NOTICE %s :Restricted mode for \2%s\2 is currently \2OFF\2.",
05566 ChanServ, from, regchan->name);
05567 return RET_SYNTAX;
05568 }
05569
05570 if (MFOUNDER > getChanOp(regchan, from)) {
05571 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
05572 return RET_NOPERM;
05573 }
05574
05575 reslevel = opNameLevel(args[2]);
05576
05577 if (reslevel == -1) {
05578 sSend(":%s NOTICE %s :No such level.", ChanServ, from);
05579 return RET_NOPERM;
05580 }
05581
05582 if (reslevel > getChanOp(regchan, from)) {
05583 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
05584 return RET_NOPERM;
05585 }
05586
05587 regchan->restrictlevel = reslevel;
05588
05589 if (tmpchan)
05590 sendToChanOps(tmpchan, "%s has set restriction to %i+ levels",
05591 from, reslevel);
05592 if (reslevel)
05593 sSend(":%s NOTICE %s :%s is now restricted to %s level.", ChanServ,
05594 from, regchan->name, opLevelName(reslevel, 2));
05595 else
05596 sSend(":%s NOTICE %s :%s is no longer in restricted mode.",
05597 ChanServ, from, regchan->name);
05598 return RET_OK_DB;
05599 }
05600
05604 cmd_return cs_set_topiclock(cs_settbl_t * cmd, UserList * nick,
05605 RegChanList * regchan, char **args,
05606 int numargs)
05607 {
05608 char *from = nick->nick;
05609 ChanList *tmpchan;
05610 int reslevel;
05611
05612 if (regchan == NULL) {
05613 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
05614 args[1]);
05615 return RET_NOTARGET;
05616 }
05617
05618 tmpchan = getChanData(regchan->name);
05619
05620 if (numargs < 3) {
05621 if (regchan->tlocklevel)
05622 sSend
05623 (":%s NOTICE %s :Topic changing for \2%s\2 currently restricted to %s.",
05624 ChanServ, from, regchan->name,
05625 opLevelName(regchan->restrictlevel, 2));
05626 else
05627 sSend
05628 (":%s NOTICE %s :The topic restriction for \2%s\2 is currently \2OFF\2.",
05629 ChanServ, from, regchan->name);
05630 return RET_SYNTAX;
05631 }
05632
05633 if (MFOUNDER > getChanOp(regchan, from)) {
05634 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
05635 return RET_NOPERM;
05636 }
05637
05638 reslevel = opNameLevel(args[2]);
05639
05640 if (reslevel == -1) {
05641 sSend(":%s NOTICE %s :No such level.", ChanServ, from);
05642 return RET_NOPERM;
05643 }
05644
05645 if (reslevel > getChanOp(regchan, from)) {
05646 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
05647 return RET_NOPERM;
05648 }
05649
05650 regchan->tlocklevel = reslevel;
05651
05652 if (tmpchan)
05653 sendToChanOps(tmpchan, "%s has set topiclock to %i+ levels", from,
05654 reslevel);
05655 if (reslevel)
05656 sSend(":%s NOTICE %s :Topic restriction for %s is now %s+.",
05657 ChanServ, from, regchan->name, opLevelName(reslevel, 2));
05658 else
05659 sSend(":%s NOTICE %s :Topic for %s is no longer restricted.",
05660 ChanServ, from, regchan->name);
05661 return RET_OK_DB;
05662 }
05663
05667 cmd_return cs_set_encrypt(cs_settbl_t * cmd, UserList * nick,
05668 RegChanList * regchan, char **args,
05669 int numargs)
05670 {
05671 char *from = nick->nick;
05672 int do_enc = 0;
05673
05674 if (numargs < 3) {
05675 sSend(":%s NOTICE %s :Password for %s is %scurrently encrypted.",
05676 ChanServ, from, regchan->name, (regchan->flags & CENCRYPT) ? "" : "not ");
05677 return RET_OK_DB;
05678 }
05679
05680 if (!str_cmp(args[2], "ON") || !str_cmp(args[2], "ENCRYPT") ||
05681 !str_cmp(args[2], "YES"))
05682 do_enc = 1;
05683 else if (!str_cmp(args[2], "OFF") || !str_cmp(args[2], "UNENCRYPT") ||
05684 !str_cmp(args[2], "NO"))
05685 do_enc = 0;
05686 else {
05687 sSend(":%s NOTICE %s :Invalid setting. Must be ON or OFF.",
05688 ChanServ, from);
05689 }
05690
05691 if (numargs < 4) {
05692 sSend(":%s NOTICE %s :Password required to change this option.",
05693 ChanServ, from);
05694 return RET_OK_DB;
05695 }
05696
05697 if (!Valid_pw(args[3], regchan->password, ChanGetEnc(regchan))) {
05698 PutReply(ChanServ, nick, ERR_BADPW, 0, 0, 0);
05699 if (BadPwChan(nick, regchan))
05700 return RET_KILLED;
05701 return RET_BADPW;
05702 }
05703 if (do_enc) {
05704 sSend(":%s NOTICE %s :Password for %s is now encrypted "
05705 "within services.", ChanServ, from, regchan->name);
05706 GoodPwChan(nick, regchan);
05707 regchan->flags |= CENCRYPT;
05708 }
05709 else {
05710 sSend(":%s NOTICE %s :Password for %s is no longer "
05711 "encrypted within services.",
05712 ChanServ, from, args[1]);
05713 regchan->flags &= ~CENCRYPT;
05714 }
05715
05716 pw_enter_password(args[3], regchan->password, ChanGetEnc(regchan));
05717
05718 return RET_OK_DB;
05719 }
05720
05724 cmd_return cs_set_mlock(cs_settbl_t * cmd, UserList * nick,
05725 RegChanList * regchan, char **args, int numargs)
05726 {
05727 struct
05728 {
05729 char character;
05730 int plus, minus;
05731 } mlock_table[] =
05732 {
05733 {
05734 'i', PM_I, MM_I}
05735 , {
05736 'm', PM_M, MM_M}
05737 , {
05738 'n', PM_N, MM_N}
05739 , {
05740 's', PM_S, MM_S}
05741 , {
05742 'p', PM_P, MM_P}
05743 , {
05744 't', PM_T, MM_T}
05745 , {
05746 'H', PM_H, MM_H}
05747 , {
05748 'c', PM_C, MM_C}
05749 , {
05750 '\0', 0, 0}
05751 };
05752
05753 int onargs = 3;
05754 int on = 1;
05755 int reset = 0;
05756 u_int i, j, klen;
05757 char mode[20], parastr[IRCBUF * 2];
05758 char *from = nick->nick;
05759
05760 ChanList *tmpchan;
05761
05762 if (!regchan)
05763 return RET_FAIL;
05764 tmpchan = getChanData(regchan->name);
05765
05766 if (regchan == NULL) {
05767 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
05768 args[1]);
05769 return RET_FAIL;
05770 }
05771
05772 if (numargs < 3) {
05773 makeModeLockStr(regchan, mode);
05774 sSend
05775 (":%s NOTICE %s :The modelock string for %s is currently \2%s\2",
05776 ChanServ, from, regchan->name, mode);
05777 return RET_OK;
05778 }
05779
05780 if (MFOUNDER > getChanOp(regchan, from)) {
05781 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
05782 return RET_NOPERM;
05783 }
05784
05785 klen = strlen(args[2]);
05786
05787 for (i = 0; i < klen; i++) {
05788 switch (args[2][i]) {
05789 default:
05790 for (j = 0; mlock_table[j].character; j++)
05791 if (mlock_table[j].character == args[2][i])
05792 break;
05793 if (mlock_table[j].character) {
05794 if (on) {
05795 regchan->mlock |= mlock_table[j].plus;
05796 regchan->mlock &= ~mlock_table[j].minus;
05797 } else {
05798 regchan->mlock |= mlock_table[j].minus;
05799 regchan->mlock &= ~mlock_table[j].plus;
05800 }
05801 }
05802 break;
05803 case '=':
05804 if (!reset) {
05805 regchan->mlock = 0;
05806 reset = 1;
05807 break;
05808 }
05809 case '+':
05810 on = 1;
05811 break;
05812 case '-':
05813 on = 0;
05814 break;
05815 case 'k':
05816 if (on) {
05817 if (numargs < onargs + 1)
05818 sSend(":%s NOTICE %s :+k not set, no key specified",
05819 ChanServ, from);
05820 else {
05821 strncpyzt(regchan->key, args[onargs], KEYLEN-1);
05822 regchan->mlock |= PM_K;
05823 regchan->mlock &= ~MM_K;
05824 onargs++;
05825 }
05826 } else {
05827 regchan->mlock |= MM_K;
05828 regchan->mlock &= ~PM_K;
05829 }
05830 break;
05831 case 'l':
05832 if (on) {
05833 if (numargs < onargs + 1)
05834 sSend(":%s NOTICE %s :+l not set, no key specified",
05835 ChanServ, from);
05836 else {
05837 regchan->limit = atoi(args[onargs]);
05838 regchan->mlock |= PM_L;
05839 regchan->mlock &= ~MM_L;
05840 onargs++;
05841 }
05842 } else {
05843 regchan->mlock |= MM_L;
05844 regchan->mlock &= ~PM_L;
05845 }
05846 break;
05847 }
05848 }
05849
05850 makeModeLockStr(regchan, mode);
05851 sendToChanOps(getChanData(regchan->name), "%s set modelock %s", from,
05852 mode);
05853 *parastr = '\0';
05854 if ((regchan->mlock & PM_L))
05855 sprintf(parastr + strlen(parastr), " %ld", regchan->limit);
05856 if ((regchan->mlock & PM_K) || (regchan->mlock & MM_K))
05857 sprintf(parastr + strlen(parastr), " %s", regchan->key
05858 && *regchan->key ? regchan->key : "*");
05859 sSend(":%s MODE %s %s%s", ChanServ, regchan->name, mode, parastr);
05860 #ifdef IRCD_MLOCK
05861 sSend(":%s MLOCK %s %s%s", ChanServ, regchan->name, mode, parastr);
05862 #endif
05863
05864 sSend(":%s NOTICE %s :Mode for %s is now locked to %s", ChanServ, from,
05865 regchan->name, mode);
05866 return RET_OK_DB;
05867 }
05868
05872
05873 cmd_return cs_set_passwd(cs_settbl_t * cmd, UserList * nick,
05874 RegChanList * regchan, char **args, int numargs)
05875 {
05876 char *from = nick->nick;
05877 char pw_reason[IRCBUF];
05878
05879 if (numargs < 3) {
05880 sSend
05881 (":%s NOTICE %s :Current password for %s cannot be shown for security reasons.",
05882 ChanServ, from, regchan->name);
05883 sSend
05884 (":%s NOTICE %s :To change the password, type \2/CHANSERV SET <CHANNEL> PASSWORD <NEWPASS>\2",
05885 ChanServ, from);
05886 sSend
05887 (":%s NOTICE %s :Or type \2/CHANSERV HELP SET PASSWORD\2 for more information",
05888 ChanServ, from);
05889 return RET_OK;
05890 }
05891
05892 if (!isFounder(regchan, nick))
05893 sSend
05894 (":%s NOTICE %s :You must identify as channel founder to change the channel password",
05895 ChanServ, from);
05896 else {
05897
05898 if (isPasswordAcceptable(args[2], pw_reason) == 0) {
05899 sSend(":%s NOTICE %s :Sorry, %s isn't a password that you can use.",
05900 ChanServ, from, args[1]);
05901 sSend(":%s NOTICE %s :%s", ChanServ, from, pw_reason);
05902 return RET_EFAULT;
05903 }
05904
05907 if (4 > strlen(args[2]) || 15 < strlen(args[2])) {
05908 sSend
05909 (":%s NOTICE %s :Please choose a password between 4 and 15 characters long",
05910 ChanServ, from);
05911 return RET_EFAULT;
05912 } else {
05913 pw_enter_password(args[2], regchan->password, ChanGetEnc(regchan));
05914 clearChanIdent(regchan);
05915
05916 sSend(":%s NOTICE %s :Password for %s is now %s", ChanServ,
05917 from, regchan->name, args[2]);
05918 return RET_OK_DB;
05919 }
05920 }
05921 return RET_OK;
05922 }
05923
05928
05929 cmd_return cs_set_founder(cs_settbl_t * cmd, UserList * nick,
05930 RegChanList * regchan, char **args, int numargs)
05931 {
05932 char *from = nick->nick;
05933 ChanList *chan = getChanData(regchan->name);
05934
05935 if (numargs < 3) {
05936 const char *tmpName = regchan->founderId.getNick();
05937
05938 if (tmpName == NULL)
05939 tmpName = "(none)";
05940
05941 sSend(":%s NOTICE %s :Current founder of \2%s\2 is \2%s\2\2",
05942 ChanServ, from, regchan->name, tmpName);
05943 return RET_OK;
05944 }
05945
05946 if (numargs < 3) {
05947 sSend(":%s NOTICE %s :To set yourself as the founder, you "
05948 "must specify the channel password.", ChanServ, from);
05949 return RET_SYNTAX;
05950 }
05951
05952 if (!nick->reg) {
05953 sSend(":%s NOTICE %s :Your nickname, %s, is not registered.", ChanServ, from,
05954 from);
05955 return RET_FAIL;
05956 }
05957
05958 if (Valid_pw(args[2], regchan->password, ChanGetEnc(regchan))) {
05959 RegNickList *founderInfo;
05960
05961 founderInfo = regchan->founderId.getNickItem();
05962
05963 if (founderInfo != NULL)
05964 founderInfo->chans--;
05965 regchan->founderId = nick->reg->regnum;
05966 nick->reg->chans++;
05967
05968 if (chan)
05969 sendToChanOps(chan, "The founder of %s is now %s",
05970 regchan->name, from);
05971 sSend(":%s NOTICE %s :You are now the founder of %s", ChanServ,
05972 from, regchan->name);
05973 GoodPwChan(nick, regchan);
05974
05975 return RET_OK_DB;
05976 }
05977 if (chan)
05978 sendToChanOps(chan, "%s failed a SET FOUNDER attempt for %s", from,
05979 chan->name);
05980 sSend(":%s NOTICE %s :Incorrect password", ChanServ, from);
05981 if (BadPwChan(nick, regchan))
05982 return RET_KILLED;
05983
05984 return RET_BADPW;
05985 }
05986
05990
05991 cmd_return cs_set_memolvl(cs_settbl_t * cmd, UserList * nick,
05992 RegChanList * regchan, char **args, int numargs)
05993 {
05994 char *from = nick->nick;
05995 int i;
05996
05997 if (numargs < 3) {
05998 sSend(":%s NOTICE %s :Current memo level for \2%s\2 is \2%d\2.",
05999 ChanServ, from, regchan->name, regchan->memolevel);
06000 return RET_SYNTAX;
06001 }
06002
06003 i = atoi(args[2]);
06004
06005 if (!((i >= MAOP) && (i <= FOUNDER))) {
06006 sSend(":%s NOTICE %s :You need to specify a valid level.",
06007 ChanServ, from);
06008 return RET_SYNTAX;
06009 }
06010
06011 regchan->memolevel = atoi(args[2]);
06012 sSend(":%s NOTICE %s :Channel memolevel is now %s", ChanServ, from,
06013 args[2]);
06014 return RET_OK_DB;
06015 }
06016
06021 CCMD(cs_save)
06022 {
06023 char *from = nick->nick;
06024
06025 if (!isRoot(nick)) {
06026 sSend(":%s NOTICE %s :Access denied.", ChanServ, from);
06027 return RET_NOPERM;
06028 }
06029
06030 #ifdef GLOBOP_ON_SAVE
06031 sSend(":%s GLOBOPS :Saving database. (%s)", ChanServ, from);
06032 #else
06033 sSend(":%s PRIVMSG " LOGCHAN " :Saving database. (%s)", ChanServ,
06034 from);
06035 #endif
06036 saveChanData(firstRegChan);
06037 return RET_OK_DB;
06038 }
06039
06040
06041
06042
06057 CCMD(cs_getpass)
06058 {
06059 char *from = nick->nick;
06060 const char *pwAuthKey;
06061 time_t doot = time(NULL);
06062 char buf[MAXBUF];
06063 int key_new, key_resend, key_transfer, i;
06064 RegNickList *regnick;
06065 RegChanList *chan;
06066 EmailMessage *email = NULL;
06067
06068 key_new = key_resend = key_transfer = 0;
06069
06070 if (numargs < 2) {
06071 sSend(":%s NOTICE %s :Must supply a channel name", ChanServ, from);
06072 return RET_SYNTAX;
06073 }
06074
06079 if (numargs >= 3)
06080 {
06081 for(i = 2; i < numargs; i++)
06082 {
06083 if (*args[i] == '-')
06084 {
06085 if (!strcmp(args[i], "-new"))
06086 key_new = 1;
06087 else if (!strcmp(args[i], "-resend"))
06088 key_resend = 1;
06089 else if (!strcmp(args[i], "-transfer") &&
06090 opFlagged(nick, OGRP) &&
06091 !is_sn_chan(args[1]))
06092 key_transfer = 1;
06093 else if (args[i][1] == '-')
06094 break;
06095 }
06096 else
06097 continue;
06098 }
06099 }
06100
06101 if (key_resend && key_new)
06102 key_resend = key_new = 0;
06103
06104 if (isOper(nick) == 0) {
06105 sSend(":%s NOTICE %s :You are not currently an IRC Operator",
06106 ChanServ, from);
06107 return RET_NOPERM;
06108 }
06109
06110 chan = getRegChanData(args[1]);
06111
06112 if (chan == NULL) {
06113 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
06114 args[1]);
06115 return RET_NOTARGET;
06116 }
06117
06118 regnick = chan->founderId.getNickItem();
06119
06120 if (regnick == NULL) {
06121 sSend(":%s NOTICE %s :There is no founder on record for "
06122 "the channel %s.",
06123 ChanServ, from, args[1]);
06124 return RET_FAIL;
06125 }
06126
06127 if (!key_transfer && (!regnick->email[0] || !strncasecmp(regnick->email, "(none)", 6))) {
06128 sSend
06129 (":%s NOTICE %s :The founder, %s, did not specify an e-mail address",
06130 NickServ, from, regnick->nick);
06131 return RET_FAIL;
06132 }
06133
06134 if (!key_transfer)
06135 {
06136 email = new EmailMessage;
06137
06138 if (!email) {
06139 sSend(":%s WALLOPS :cs_getpass: fatal error: out of memory",
06140 ChanServ);
06141 abort();
06142 return RET_EFAULT;
06143 }
06144 }
06145
06146 if (!key_resend && !key_new && chan->chpw_key)
06147 {
06148 sSend(":%s NOTICE %s :A password change key has already been "
06149 "issued for %s. Please specify -new or -resend.",
06150 ChanServ, from, chan->name);
06151 return RET_FAIL;
06152 }
06153 else if (key_transfer || (chan->flags & CFORCEXFER)) {
06154 if (!chan->chpw_key || !key_resend)
06155 chan->chpw_key = lrand48();
06156 if (!chan->chpw_key)
06157 chan->chpw_key = 1;
06158 pwAuthKey = GetAuthChKey("-forced-transfer-",
06159 PrintPass(chan->password, ChanGetEnc(chan)),
06160 chan->timereg,
06161 chan->chpw_key);
06162 if (key_transfer)
06163 sSend(":%s GLOBOPS :%s used getpass (transfer) on %s", ChanServ, from, chan->name);
06164 else
06165 sSend(":%s GLOBOPS :%s used getpass (getkey) on %s", ChanServ, from, chan->name);
06166 sSend(":%s NOTICE %s :The change auth key for %s is: %s",
06167 ChanServ, from, chan->name, pwAuthKey);
06168 operlog->log(nick, CSS_GETPASS_XFER, args[1]);
06169 chan->flags |= CFORCEXFER;
06170 clearChanIdent(chan);
06171
06172 return RET_OK_DB;
06173 }
06174 else if ((chan->flags & CFORCEXFER) && !opFlagged(nick, OGRP | OOPER | OVERRIDE))
06175 {
06176 sSend(":%s NOTICE %s :This chan's pw key was marked ``channel transfer''",
06177 ChanServ, from);
06178 return RET_FAIL;
06179 }
06180
06181
06182 if (!key_resend || key_new)
06183 key_new = key_resend = 0;
06184
06185 sSend(":%s GLOBOPS :%s used sendpass on %s", myname, from, chan->name);
06186 sSend
06187 (":%s NOTICE %s :The \2password change key\2 has been sent to the email address: "
06188 "%s", ChanServ, from, regnick->email);
06189 snprintf(buf, sizeof(buf), "%s Password Recovery <%s@%s>", ChanServ,
06190 ChanServ, NETWORK);
06191
06192 if (!chan->chpw_key || !key_resend || key_new) {
06193 chan->chpw_key = lrand48();
06194 }
06195 if (!chan->chpw_key)
06196 chan->chpw_key = 1;
06197 pwAuthKey = GetAuthChKey(regnick->email, PrintPass(chan->password, ChanGetEnc(chan)), chan->timereg,
06198 chan->chpw_key);
06199
06200 email->from = buf;
06201 email->subject = "Password";
06202 email->to = regnick->email;
06203 sprintf(buf,
06204 "\nThe password change key for %.*s is %.*s\n"
06205 "\nType /CHANSERV SETPASS %.*s %.*s <password>\n",
06206 CHANLEN, chan->name,
06207 255, pwAuthKey,
06208 CHANLEN, chan->name,
06209 255, pwAuthKey
06210 );
06211 email->body = buf;
06212
06213
06214 email->body += "Or navigate to: "
06215 "http://astral.sorcery.net/~sortest/setpass.php?u_chan=";
06216 email->body += urlEncode(chan->name);
06217 email->body += "&u_ck=";
06218 email->body += urlEncode(pwAuthKey);
06219 email->body += "\nTo set a new channel password.\n\n";
06220
06221 sprintf(buf, "Retrieved by %.*s at %s",
06222 NICKLEN, from, ctime(&(doot)));
06223 email->body += buf;
06224 email->send();
06225 email->reset();
06226 operlog->log(nick, CS_GETPASS, args[1]);
06227
06228 delete email;
06229
06230 return RET_OK_DB;
06231 }
06232
06233
06234
06235
06242 CCMD(cs_getrealpass)
06243 {
06244 char *from = nick->nick;
06245 RegChanList *chan;
06246
06247
06248 if (!isRoot(nick)) {
06249 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
06250 return RET_NOPERM;
06251 }
06252
06253 if (!opFlagged(nick, OROOT | OVERRIDE)) {
06254 sSend(":%s NOTICE %s :Restricted -- getrealpass is a debugging and administrative command not for password recovery.",
06255 ChanServ, from);
06256 return RET_NOPERM;
06257 }
06258
06259 if (numargs != 2) {
06260 sSend(":%s NOTICE %s :Must supply a channel name", ChanServ, from);
06261 return RET_SYNTAX;
06262 }
06263
06264 chan = getRegChanData(args[1]);
06265
06266 if (chan == NULL) {
06267 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from,
06268 args[1]);
06269 return RET_NOTARGET;
06270 }
06271
06272 sSend(":%s GLOBOPS :%s used getrealpass on %s", ChanServ, from,
06273 chan->name);
06274 if (!(chan->flags & CENCRYPT))
06275 sSend(":%s NOTICE %s :The password for %s is %s", ChanServ, from,
06276 args[1], chan->password);
06277 else {
06278 u_char *p = toBase64(chan->password, 16);
06279
06280 sSend(":%s NOTICE %s :The password for %s is encrypted: %s", ChanServ, from,
06281 args[1], md5_printable(chan->password));
06282 if (p) {
06283 sSend(":%s NOTICE %s :Base64 representation: $%s", ChanServ, from,
06284 p);
06285 FREE(p);
06286 }
06287 }
06288 operlog->log(nick, CS_GETREALPASS, args[1]);
06289 return RET_OK;
06290 }
06291
06292
06293
06305 CCMD(cs_invite)
06306 {
06307 char *from = nick->nick;
06308 int override = 0;
06309 RegChanList *chan;
06310
06311 override = opFlagged(nick, OOPER | OVERRIDE) ? 1 : 0;
06312
06313 if (numargs < 2) {
06314 sSend(":%s NOTICE %s :You must specify a channel.", ChanServ,
06315 from);
06316 return RET_SYNTAX;
06317 }
06318
06319 chan = getRegChanData(args[1]);
06320
06321 if (override && chan == NULL) {
06322 sSend(":%s INVITE %s %s", ChanServ, from, args[1]);
06323 if (override)
06324 sSend(":%s GLOBOPS :%s uses override invite (%s)", ChanServ,
06325 from, args[1]);
06326 return RET_OK;
06327 }
06328
06329 if (chan == NULL) {
06330 sSend(":%s NOTICE %s :%s isn't registered", ChanServ, from,
06331 args[1]);
06332 return RET_NOTARGET;
06333 }
06334
06335 if ((getChanOp(chan, from) < chan->restrictlevel)) {
06336 sSend(":%s NOTICE %s :%s is currently restricted to chanop "
06337 "levels %d (%s+) and up.", ChanServ, from, chan->name,
06338 chan->restrictlevel, opLevelName(chan->restrictlevel, 0));
06339 return RET_NOPERM;
06340 }
06341
06342 if (1 > getChanOp(chan, from) && !override) {
06343 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
06344 return RET_NOPERM;
06345 } else {
06346 sSend(":%s NOTICE %s :Giving you an invitation for %s...",
06347 ChanServ, from, chan->name);
06348 sSend(":%s INVITE %s %s", ChanServ, from, chan->name);
06349
06350 if (!getChanData(chan->name))
06351 sSend(":%s NOTICE %s :Error: %s is empty.", ChanServ, from,
06352 chan->name);
06353
06354 if (override && chan)
06355 sSend(":%s GLOBOPS :%s uses override invite (%s)", ChanServ,
06356 from, chan->name);
06357 }
06358
06359 return RET_OK;
06360 }
06361
06362
06363
06374 CCMD(cs_unban)
06375 {
06376 char *from = nick->nick;
06377 RegChanList *chan;
06378 ChanList *tmp;
06379 cBanList *tmpban;
06380 cBanList *next;
06381 int a, domodes = 0;
06382 char mode[(USERLEN + HOSTLEN + HOSTLEN) * 6 + 5] = "";
06383 char userhost[NICKLEN + USERLEN + HOSTLEN];
06384 char userhostM[NICKLEN + USERLEN + HOSTLEN];
06385
06386 tmp = getChanData(args[1]);
06387 chan = getRegChanData(args[1]);
06388
06389 if (tmp == NULL || chan == NULL) {
06390 sSend(":%s NOTICE %s :The channel must be registered, and in use.",
06391 ChanServ, from);
06392 return RET_NOTARGET;
06393 }
06394 a = getChanOp(chan, from);
06395
06396 if (a < AOP) {
06397 sSend(":%s NOTICE %s :You do not have sufficient access to %s",
06398 ChanServ, from, args[1]);
06399 if (a > 0)
06400 sSend
06401 (":%s NOTICE %s :try \2/msg ChanServ INVITE %s\2 instead.",
06402 ChanServ, from, args[1]);
06403 return RET_NOPERM;
06404 }
06405
06406 if ((numargs < 3) || !strcasecmp(args[2], "me")
06407 || !strcasecmp(args[2], from)) {
06408 snprintf(userhost, sizeof(userhost), "%s!%s@%s", nick->nick,
06409 nick->user, nick->host);
06410 snprintf(userhostM, sizeof(userhost), "%s!%s@%s", nick->nick,
06411 nick->user, genHostMask(nick->host));
06412 for (tmpban = tmp->firstBan; tmpban; tmpban = next) {
06413 next = tmpban->next;
06414
06415 if (match(tmpban->ban, userhost) == 0
06416 || match(tmpban->ban, userhostM) == 0) {
06417 strcat(mode, tmpban->ban);
06418 strcat(mode, " ");
06419 domodes++;
06420 sSend(":%s NOTICE %s :You are no longer banned on %s (%s)",
06421 ChanServ, from, args[1], tmpban->ban);
06422 delChanBan(tmp, tmpban);
06423 }
06424 if (domodes > 0 && (domodes == 6 || next == NULL)) {
06425 sSend(":%s NOTICE %s :Removed bans: %s", ChanServ, from,
06426 mode);
06427 sSend(":%s MODE %s -bbbbbb %s", ChanServ, args[1], mode);
06428 domodes = 0;
06429 mode[0] = 0;
06430 }
06431 }
06432 } else if (!strcasecmp(args[2], "all") || !strcasecmp(args[2], "*")) {
06433 if (a < MSOP)
06434 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
06435 else {
06436 for (tmpban = tmp->firstBan; tmpban; tmpban = next) {
06437 next = tmpban->next;
06438
06439 strcat(mode, tmpban->ban);
06440 strcat(mode, " ");
06441 domodes++;
06442 if (domodes == 6 || next == NULL) {
06443 sSend(":%s NOTICE %s :Removed bans: %s", ChanServ,
06444 from, mode);
06445 sSend(":%s MODE %s -bbbbbb %s", ChanServ, args[1],
06446 mode);
06447 domodes = 0;
06448 mode[0] = 0;
06449 }
06450 delChanBan(tmp, tmpban);
06451
06452 }
06453 }
06454 } else {
06455 if (a < MSOP) {
06456 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
06457 } else {
06458 for (tmpban = tmp->firstBan; tmpban; tmpban = next) {
06459 next = tmpban->next;
06460
06461 if (!match(args[2], tmpban->ban)) {
06462 strcat(mode, tmpban->ban);
06463 strcat(mode, " ");
06464 domodes++;
06465 delChanBan(tmp, tmpban);
06466 }
06467 if (domodes > 0 && (domodes == 6 || next == NULL)) {
06468 sSend(":%s NOTICE %s :Removed bans: %s", ChanServ,
06469 from, mode);
06470 sSend(":%s MODE %s -bbbbbb %s", ChanServ, args[1],
06471 mode);
06472 domodes = 0;
06473 mode[0] = 0;
06474 }
06475 }
06476 }
06477 }
06478 return RET_OK;
06479 }
06480
06481
06482
06494 CCMD(cs_list)
06495 {
06496 char *from = nick->nick;
06497 int i, x;
06498 RegChanList *reg;
06499 RegNickList *rnl = NULL;
06500 short byfounder = 0;
06501
06502 i = x = 0;
06503
06504 if (!isServop(nick) && !opFlagged(nick, OOPER | OLIST)) {
06505 sSend(":%s NOTICE %s :Permission denied.", ChanServ, from);
06506 return RET_NOPERM;
06507 }
06508
06509 if (numargs < 2) {
06510 sSend(":%s NOTICE %s :You must specify a mask or -f", ChanServ,
06511 from);
06512 return RET_SYNTAX;
06513 }
06514
06515 if (strncmp(args[1], "-f", 2) == 0)
06516 if (numargs < 3) {
06517 sSend(":%s NOTICE %s :You must specify a founder nick with -f",
06518 ChanServ, from);
06519 return RET_SYNTAX;
06520 } else {
06521 byfounder = 1;
06522 rnl = getRegNickData(args[2]);
06523 }
06524
06525 for (reg = firstRegChan; reg; reg = reg->next) {
06526 if (byfounder == 1) {
06527 if (rnl && rnl->regnum == reg->founderId) {
06528 i++;
06529 sSend(":%s NOTICE %s :%4i: %s %s (%s)", ChanServ, from, i,
06530 reg->name, rnl->nick, reg->desc);
06531 }
06532 } else {
06533 if (!match(args[1], reg->name)) {
06534 const char *tmpNick = reg->founderId.getNick();
06535
06536 if (tmpNick == NULL)
06537 tmpNick = "(none)";
06538
06539 i++;
06540 sSend(":%s NOTICE %s :%4i: %s %s (%s)", ChanServ, from, i,
06541 reg->name, tmpNick, reg->desc);
06542 }
06543 }
06544 x++;
06545 }
06546
06547 sSend(":%s NOTICE %s :%i/%i matched conditions (%s)", ChanServ, from,
06548 i, x, (byfounder == 1) ? args[2] : args[1]);
06549 if (byfounder == 1)
06550 sSend(":%s GLOBOPS :%s is listing founder nick %s (%d/%d matches)", ChanServ, from,
06551 args[2], i, x);
06552 else
06553 sSend(":%s GLOBOPS :%s is listing %s (%d/%d matches)", ChanServ, from, args[1], i, x);
06554 return RET_OK;
06555 }
06556
06557
06558
06565 CCMD(cs_delete)
06566 {
06567 char *from = nick->nick;
06568 int i, x;
06569 RegChanList *reg;
06570 ChanList *chan;
06571
06572 i = x = 0;
06573
06574 if (!isServop(nick) && !opFlagged(nick, OOPER | OCBANDEL)) {
06575 sSend(":%s NOTICE %s :Permission denied.", ChanServ, from);
06576 return RET_NOPERM;
06577 }
06578
06579 if (numargs < 2) {
06580 sSend(":%s NOTICE %s :You must specify a channel to delete.",
06581 ChanServ, from);
06582 return RET_SYNTAX;
06583 }
06584
06585
06586 if (is_sn_chan(args[1]) && !opFlagged(nick, OOPER | OSERVOP | OVERRIDE)) {
06587 sSend(":%s NOTICE %s :You can't delete that chan!", ChanServ,
06588 from);
06589 sSend(":%s GLOBOPS :%s tried to use DROP command on %s", ChanServ,
06590 from, args[1]);
06591 chanlog->log(nick, CS_DELETE, args[1], LOGF_FAIL | LOGF_OPER);
06592 return RET_OK_DB;
06593 }
06594
06595
06596 if (!(reg = getRegChanData(args[1]))) {
06597 sSend(":%s NOTICE %s :That channel is not registered.", ChanServ,
06598 from);
06599 return RET_NOTARGET;
06600 }
06601
06602 if (addFlood(nick, 25))
06603 return RET_KILLED;
06604
06605 if ((reg->flags & CHOLD) && !opFlagged(nick, OROOT)) {
06606 sSend
06607 (":%s NOTICE %s :That is a held channel.",
06608 ChanServ, from);
06609 sSend(":%s GLOBOPS :%s tried to use DROP command on %s", ChanServ,
06610 from, args[1]);
06611 chanlog->log(nick, CS_DELETE, args[1], LOGF_FAIL | LOGF_OPER);
06612 return RET_OK_DB;
06613 }
06614
06615 sSend(":%s GLOBOPS :%s used DROP command on %s", ChanServ, from,
06616 args[1]);
06617
06618 chanlog->log(nick, CS_DELETE, args[1], LOGF_OPER);
06619 if ((chan = getChanData(args[1])))
06620 chan->reg = NULL;
06621 delRegChan(reg);
06622 return RET_OK_DB;
06623 }
06624
06625
06626
06634 CCMD(cs_log)
06635 {
06636 char *from = nick->nick;
06637 char log_str[IRCBUF + 1];
06638
06639 if (addFlood(nick, 5))
06640 return RET_KILLED;
06641
06642 if (isOper(nick) == 0) {
06643 sSend(":%s NOTICE %s :Access denied", ChanServ, from);
06644 return RET_NOPERM;
06645 }
06646
06647 if (numargs < 2) {
06648 sSend(":%s NOTICE %s :Must supply at least one argument", ChanServ,
06649 from);
06650 return RET_SYNTAX;
06651 }
06652
06653 bzero(log_str, IRCBUF);
06654 parse_str(args, numargs, 1, log_str, IRCBUF);
06655
06656 if (strlen(log_str) < 2) {
06657 sSend(":%s NOTICE %s :Logline too short.", ChanServ, from);
06658 return RET_EFAULT;
06659 }
06660 if (strlen(log_str) >= (IRCBUF - 1)) {
06661 sSend(":%s NOTICE %s :Logline too long.", ChanServ, from);
06662 return RET_EFAULT;
06663 }
06664
06665 sSend(":%s NOTICE %s :Ok, logged.", ChanServ, from);
06666 chanlog->log(nick, CS_LOG, NULL, 0, "%s", log_str);
06667 return RET_OK_DB;
06668 }
06669
06670
06671
06679 CCMD(cs_setpass)
06680 {
06681 const char *from = nick->nick;
06682 const char *pwAuthChKey;
06683 RegChanList *rcl;
06684 RegNickList *rfl;
06685
06686 if (numargs < 4)
06687 {
06688 sSend(":%s NOTICE %s :Syntax: SETPASS <channel> <code> <new password>",
06689 ChanServ, from);
06690 return RET_SYNTAX;
06691 }
06692
06693 if ((rcl = getRegChanData(args[1])) == NULL)
06694 {
06695 sSend(":%s NOTICE %s :That channel is not registered.",
06696 NickServ, from);
06697 return RET_NOTARGET;
06698 }
06699
06700 rfl = rcl->founderId.getNickItem();
06701
06702 if (rfl && rcl->chpw_key) {
06703 if (rcl->flags & CFORCEXFER)
06704 pwAuthChKey = GetAuthChKey("-forced-transfer-", PrintPass(rcl->password, ChanGetEnc(rcl)),
06705 rcl->timereg, rcl->chpw_key);
06706 else
06707 pwAuthChKey = GetAuthChKey(rfl->email, PrintPass(rcl->password, ChanGetEnc(rcl)),
06708 rcl->timereg, rcl->chpw_key);
06709 }
06710 else
06711 pwAuthChKey = NULL;
06712
06713 if (pwAuthChKey == NULL || strcmp(pwAuthChKey, args[2]))
06714 {
06715 sSend(":%s NOTICE %s :Access Denied.",
06716 ChanServ, from);
06717 return RET_FAIL;
06718 }
06719
06720 if (strlen(args[3]) > PASSLEN)
06721 {
06722 sSend(":%s NOTICE %s :Specified password is too long, please "
06723 "choose a password of %d characters or less.",
06724 ChanServ, from, PASSLEN);
06725 return RET_EFAULT;
06726 }
06727
06728
06729 if (strcasecmp(args[1], args[3]) == 0 || strcasecmp(args[3], "password") == 0
06730 || strlen(args[3]) < 3)
06731 {
06732 sSend(":%s NOTICE %s :You cannot use \2%s\2 as your channel password.",
06733 ChanServ, from, args[3]);
06734 return RET_EFAULT;
06735 }
06736
06737 sSend(":%s NOTICE %s :Ok.", ChanServ, from);
06738
06739 rcl->flags |= CENCRYPT;
06740 rcl->chpw_key = 0;
06741 rcl->flags &= ~CFORCEXFER;
06742 pw_enter_password(args[3], rcl->password, ChanGetEnc(rcl));
06743 clearChanIdent(rcl);
06744
06745 sSend(":%s NOTICE %s :The password for %s is now %s, do NOT forget it, we"
06746 " are not responsible for lost passwords.",
06747 ChanServ, from, rcl->name, args[3]);
06748
06749 return RET_OK_DB;
06750 }
06751
06755 NCMD(cs_setrealpass)
06756 {
06757 char* from = nick->nick;
06758 RegChanList* chn;
06759
06760 if (!opFlagged(nick, OOPER | OGRP)) {
06761 sSend(":%s NOTICE %s :Permission denied -- this command is "
06762 "provided for PWops/GRPops.", ChanServ, from);
06763
06764 return RET_NOPERM;
06765 }
06766
06767 if (numargs < 2) {
06768 sSend(":%s NOTICE %s :Syntax Error: Channel name missing.",
06769 ChanServ, from);
06770 return RET_SYNTAX;
06771 }
06772
06773 if (numargs < 3) {
06774 sSend(":%s NOTICE %s :Syntax Error: Password missing.",
06775 ChanServ, from);
06776 return RET_SYNTAX;
06777 }
06778
06779 chn = getRegChanData(args[1]);
06780
06781 if (chn == NULL) {
06782 sSend(":%s NOTICE %s :Setrealpass error: channel is not registered.",
06783 ChanServ, from);
06784 return RET_NOTARGET;
06785 }
06786
06787 if ((!isRoot(nick) || !opFlagged(nick, OVERRIDE)) && is_sn_chan(args[1])) {
06788 sSend(":%s NOTICE %s :Permission denied: magic channel.",
06789 ChanServ, from);
06790 return RET_NOPERM;
06791 }
06792
06793 pw_enter_password(args[2], chn->password, ChanGetEnc(chn));
06794 sSend(":%s NOTICE %s :New password installed.",
06795 ChanServ, from);
06796
06797 return RET_OK_DB;
06798 }
06799
06800
06801
06823 CCMD(cs_trigger)
06824 {
06825
06826
06827
06828 ChanTrigger* trg;
06829 char* from = nick->nick;
06830
06831 if (!isOper(nick) || !isRoot(nick)) {
06832 PutReply(ChanServ, nick, ERR_NOACCESS, 0, 0, 0);
06833 return RET_NOPERM;
06834 }
06835
06853 if (numargs == 1) {
06854
06855 sSend(":%s NOTICE %s :Default Values:", ChanServ, nick->nick);
06856 sSend(":%s NOTICE %s :MaxOps(%d), MaxAkicks(%d)", ChanServ, nick->nick, OpLimit, AkickLimit);
06857 return RET_OK;
06858 }
06859
06860 if (numargs < 2) {
06861 sSend(":%s NOTICE %s :Syntax: TRIGGER [<channel> [<item> <value>]]", ChanServ, nick->nick);
06862 sSend(":%s NOTICE %s : TRIGGER <channel> DEFAULTS", ChanServ, nick->nick);
06863 return RET_SYNTAX;
06864 }
06865
06866
06867 if (!str_cmp(args[1], "LIST")) {
06868 long hashEnt;
06869
06870
06871 sSend(":%s NOTICE %s :%-30s %-3s %-3s", ChanServ, from, "Channel", "Ops", "Aks");
06872
06873 for(hashEnt = 0; hashEnt < CHANTRIGHASHSIZE; hashEnt++)
06874 for(trg = LIST_FIRST(&ChanTrigHash[hashEnt]); trg;
06875 trg = LIST_NEXT(trg, cn_lst))
06876 {
06877 sSend(":%s NOTICE %s :%-30s %-3d %-3d", ChanServ,
06878 from, trg->chan_name, DEFIFZERO(trg->op_trigger, OpLimit), DEFIFZERO(trg->ak_trigger, AkickLimit));
06879 }
06880 return RET_OK;
06881 }
06882
06883 if (ValidChannelName(args[1]) == 0) {
06884 PutReply(ChanServ, nick, ERR_CS_INVALIDCHAN_1ARG, args[1], 0, 0);
06885 return RET_EFAULT;
06886 }
06887
06888 if (getRegChanData(args[1]) == 0) {
06889 PutReply(ChanServ, nick, ERR_CHANNOTREG_1ARG, args[1], 0, 0);
06890 return RET_NOTARGET;
06891 }
06892
06893 trg = FindChannelTrigger(args[1]);
06894
06895 if (numargs == 2) {
06896
06897 sSend(":%s NOTICE %s :%s:", ChanServ, nick->nick, args[1]);
06898
06899 if (trg)
06900 sSend(":%s NOTICE %s :MaxOps(%d) MaxAkicks(%d)", ChanServ, nick->nick,
06901 DEFIFZERO(trg->op_trigger, OpLimit), DEFIFZERO(trg->ak_trigger, AkickLimit));
06902 else
06903 sSend(":%s NOTICE %s :MaxOps(%d) MaxAkicks(%d)", ChanServ, nick->nick,
06904 OpLimit, AkickLimit);
06905 return RET_OK;
06906 }
06907
06908 {
06909 int k = -1;
06910
06911 if (!str_cmp(args[2], "MaxOps"))
06912 k = 0;
06913 else if (!str_cmp(args[2], "MaxAkicks"))
06914 k = 1;
06915
06916 if (k == -1 && (numargs != 4 || (numargs > 3 && args[3] && !isdigit(args[3][0])))) {
06917 if (!str_cmp(args[2], "DEFAULTS")) {
06918
06919
06920
06921
06922
06923 if (trg) {
06924 DelChannelTrigger(trg);
06925 FreeChannelTrigger(trg);
06926
06927 return RET_OK_DB;
06928 }
06929 return RET_NOTARGET;
06930 }
06931
06932 return RET_SYNTAX;
06933 }
06934
06935 if (k == -1) {
06936 PutReply(ChanServ, nick, ERR_INVALID_TRIGVAR, 0, 0, 0);
06937 return RET_SYNTAX;
06938 }
06939
06940 if (!trg) {
06941 trg = MakeChannelTrigger(args[1]);
06942 AddChannelTrigger(trg);
06943 }
06944
06945 if (k == 0)
06946 trg->op_trigger = atoi(args[3]);
06947 if (k == 1)
06948 trg->ak_trigger = atoi(args[3]);
06949
06950
06951
06952
06953
06954
06955 return RET_OK_DB;
06956 }
06957
06958 return RET_FAIL;
06959 }
06960
06961
06962
06963 CCMD(cs_dmod)
06964 {
06965 RegChanList *chan;
06966 typedef enum { DMOD_UNDEFINED, DMOD_HELP, DMOD_TOPIC,
06967 DMOD_FOUNDER } dModItem;
06968 dModItem tar = DMOD_UNDEFINED;
06969 char* from = nick->nick;
06970 int i;
06971
06972 if (!isOper(nick) || !opFlagged(nick, ODMOD)) {
06973 PutReply(ChanServ, nick, ERR_NOACCESS, 0, 0, 0);
06974 return RET_NOPERM;
06975 }
06976
06977 #define DMOD_KEY(nm, va) else if (strcmp(args[i], nm) == 0) {tar=(va); i++; break;}
06978
06979 for(i = 1; i < numargs; i++) {
06980 if (args[i][0] != '-')
06981 break;
06982
06983 if (0);
06984 DMOD_KEY("-help", DMOD_HELP)
06985 DMOD_KEY("-topic", DMOD_TOPIC)
06986 DMOD_KEY("-founder", DMOD_FOUNDER)
06987 }
06988
06989 if (tar == DMOD_UNDEFINED) {
06990 sSend(":%s NOTICE %s :An action is required. See \2/cs help dmod\2 for more information.", ChanServ, from);
06991 return RET_SYNTAX;
06992 }
06993
06994 if (i >= numargs) {
06995 sSend(":%s NOTICE %s :This command requires a channel.", ChanServ, from);
06996 return RET_SYNTAX;
06997 }
06998
06999 if (i + 1 >= numargs) {
07000 sSend(":%s NOTICE %s :To what value?", ChanServ, from);
07001 return RET_SYNTAX;
07002 }
07003
07004 chan = getRegChanData(args[i]);
07005 if (!chan) {
07006 sSend(":%s NOTICE %s :%s is not registered", ChanServ, from, args[1]);
07007 return RET_NOTARGET;
07008 }
07009
07010 rshift_argv(args, i, numargs);
07011 numargs -= (i);
07012
07013 switch( tar ) {
07014 case DMOD_FOUNDER :
07015 {
07016 RegNickList* reg = getRegNickData(args[1]);
07017
07018 if (reg == NULL) {
07019 PutReply(ChanServ, nick, ERR_NICKNOTREG_1ARG,
07020 args[1], 0, 0);
07021 return RET_NOTARGET;
07022 }
07023
07024 chan->founderId = reg->regnum;
07025
07026 sSend(":%s NOTICE %s :%s now founder of %s.",
07027 ChanServ, from, reg->nick, chan->name);
07028 return RET_OK_DB;
07029 }
07030 case DMOD_TOPIC:
07031 {
07032 char buf[TOPIC_MAX+1];
07033 parse_str(args, numargs, 1, buf, TOPIC_MAX);
07034 if (strcmp(buf, "*") == 0)
07035 buf[0] = '\0';
07036 if (chan->topic)
07037 FREE(chan->topic);
07038 chan->topic = static_cast<char *>(oalloc(strlen(buf)));
07039 strcpy(chan->topic, buf);
07040 strncpyzt(chan->tsetby, nick->nick, NICKLEN);
07041 return RET_OK_DB;
07042 }
07043 break;
07044 default:;
07045 break;
07046 }
07047
07048 return RET_EFAULT;
07049 }
07050
07051
07052
07053
07054