cmdschan.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438
  1. /*
  2. * Copyright (C) 1997 Robey Pointer
  3. * Copyright (C) 1999 - 2002 Eggheads Development Team
  4. * Copyright (C) 2002 - 2010 Bryan Drewery
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. /*
  21. * cmdschan.c -- part of channels.mod
  22. * commands from a user via dcc that cause server interaction
  23. *
  24. */
  25. #include <ctype.h>
  26. #include "src/mod/console.mod/console.h"
  27. static struct flag_record user = {FR_GLOBAL | FR_CHAN, 0, 0, 0 };
  28. static struct flag_record victim = {FR_GLOBAL | FR_CHAN, 0, 0, 0 };
  29. static void cmd_pls_mask(const char type, int idx, char *par)
  30. {
  31. const char *cmd = (type == 'b' ? "ban" : type == 'e' ? "exempt" : "invite");
  32. if (!par[0]) {
  33. usage:
  34. dprintf(idx, "Usage: +%s <hostmask> [channel] [%%<XdXhXm>] [reason]\n", cmd);
  35. return;
  36. }
  37. char *chname = NULL, *who = NULL, s[UHOSTLEN] = "", s1[UHOSTLEN] = "", *p = NULL, *p_expire = NULL;
  38. unsigned long int expire_time = 0, expire_foo;
  39. int sticky = 0;
  40. struct chanset_t *chan = NULL;
  41. who = newsplit(&par);
  42. if (par[0] && strchr(CHANMETA, par[0]))
  43. chname = newsplit(&par);
  44. /* Did they mix up the two params? */
  45. if (!chname && strchr(CHANMETA, who[0])) {
  46. if (par[0]) {
  47. chname = who;
  48. who = newsplit(&par);
  49. } else {
  50. goto usage;
  51. }
  52. }
  53. if (chname || !(dcc[idx].user->flags & USER_MASTER)) {
  54. if (!chname)
  55. chname = dcc[idx].u.chat->con_chan;
  56. get_user_flagrec(dcc[idx].user, &user, chname);
  57. chan = findchan_by_dname(chname);
  58. /* *shrug* ??? (guppy:10Feb1999) */
  59. if (!chan || (chan && privchan(user, chan, PRIV_OP))) {
  60. dprintf(idx, "No such channel.\n");
  61. return;
  62. } else if (!chk_op(user, chan)) {
  63. dprintf(idx, "You don't have access to set %ss on %s.\n", cmd, chname);
  64. return;
  65. }
  66. } else
  67. chan = 0;
  68. /* Added by Q and Solal -- Requested by Arty2, special thanx :) */
  69. if (par[0] == '%') {
  70. p = newsplit(&par);
  71. p_expire = p + 1;
  72. while (*(++p) != 0) {
  73. switch (tolower(*p)) {
  74. case 'd':
  75. *p = 0;
  76. expire_foo = strtol(p_expire, NULL, 10);
  77. if (expire_foo > 365)
  78. expire_foo = 365;
  79. expire_time += 86400 * expire_foo;
  80. p_expire = p + 1;
  81. break;
  82. case 'h':
  83. *p = 0;
  84. expire_foo = strtol(p_expire, NULL, 10);
  85. if (expire_foo > 8760)
  86. expire_foo = 8760;
  87. expire_time += 3600 * expire_foo;
  88. p_expire = p + 1;
  89. break;
  90. case 'm':
  91. *p = 0;
  92. expire_foo = strtol(p_expire, NULL, 10);
  93. if (expire_foo > 525600)
  94. expire_foo = 525600;
  95. expire_time += 60 * expire_foo;
  96. p_expire = p + 1;
  97. }
  98. }
  99. }
  100. if (!par[0])
  101. par = "requested";
  102. else if (strlen(par) > MASKREASON_MAX)
  103. par[MASKREASON_MAX] = 0;
  104. if (strlen(who) > UHOSTMAX - 4)
  105. who[UHOSTMAX - 4] = 0;
  106. /* Fix missing ! or @ BEFORE checking against myself */
  107. if (!strchr(who, '!')) {
  108. if (!strchr(who, '@'))
  109. simple_snprintf(s, sizeof s, "%s!*@*", who); /* Lame nick ban */
  110. else
  111. simple_snprintf(s, sizeof s, "*!%s", who);
  112. } else if (!strchr(who, '@'))
  113. simple_snprintf(s, sizeof s, "%s@*", who); /* brain-dead? */
  114. else
  115. strlcpy(s, who, sizeof s);
  116. if (conf.bot->hub)
  117. simple_snprintf(s1, sizeof s1, "%s!%s@%s", origbotname, botuser, conf.bot->net.host);
  118. else
  119. simple_snprintf(s1, sizeof s1, "%s!%s", botname, botuserhost);
  120. if (type == 'b' && s1[0] && wild_match(s, s1)) {
  121. dprintf(idx, "I'm not going to ban myself.\n");
  122. putlog(LOG_CMDS, "*", "#%s# attempted +ban %s", dcc[idx].nick, s);
  123. return;
  124. }
  125. /* IRC can't understand bans longer than 70 characters */
  126. if (strlen(s) > 70) {
  127. s[69] = '*';
  128. s[70] = 0;
  129. }
  130. if (chan) {
  131. u_addmask(type, chan, s, dcc[idx].nick, par, expire_time ? now + expire_time : 0, 0);
  132. if (par[0] == '*') {
  133. sticky = 1;
  134. par++;
  135. putlog(LOG_CMDS, "*", "#%s# (%s) +%s %s %s (%s) (sticky)", dcc[idx].nick, dcc[idx].u.chat->con_chan, cmd, s, chan->dname, par);
  136. dprintf(idx, "New %s sticky %s: %s (%s)\n", chan->dname, cmd, s, par);
  137. } else {
  138. putlog(LOG_CMDS, "*", "#%s# (%s) +%s %s %s (%s)", dcc[idx].nick, dcc[idx].u.chat->con_chan, cmd, s, chan->dname, par);
  139. dprintf(idx, "New %s %s: %s (%s)\n", chan->dname, cmd, s, par);
  140. }
  141. if (!conf.bot->hub) {
  142. if (type == 'e' || type == 'I')
  143. add_mode(chan, '+', type, s);
  144. /* Avoid unnesessary modes if you got +dynamicbans
  145. */
  146. else
  147. check_this_ban(chan, s, sticky);
  148. } else
  149. write_userfile(idx);
  150. } else {
  151. u_addmask(type, NULL, s, dcc[idx].nick, par, expire_time ? now + expire_time : 0, 0);
  152. if (par[0] == '*') {
  153. sticky = 1;
  154. par++;
  155. putlog(LOG_CMDS, "*", "#%s# (GLOBAL) +%s %s (%s) (sticky)", dcc[idx].nick, cmd, s, par);
  156. dprintf(idx, "New sticky %s: %s (%s)\n", cmd, s, par);
  157. } else {
  158. putlog(LOG_CMDS, "*", "#%s# (GLOBAL) +%s %s (%s)", dcc[idx].nick, cmd, s, par);
  159. dprintf(idx, "New %s: %s (%s)\n", cmd, s, par);
  160. }
  161. if (!conf.bot->hub) {
  162. for (chan = chanset; chan != NULL; chan = chan->next) {
  163. if (type == 'b')
  164. check_this_ban(chan, s, sticky);
  165. else
  166. add_mode(chan, '+', type, s);
  167. }
  168. } else
  169. write_userfile(idx);
  170. }
  171. }
  172. static void cmd_pls_ban(int idx, char *par)
  173. {
  174. cmd_pls_mask('b', idx, par);
  175. }
  176. static void cmd_pls_exempt(int idx, char *par)
  177. {
  178. cmd_pls_mask('e', idx, par);
  179. }
  180. static void cmd_pls_invite(int idx, char *par)
  181. {
  182. cmd_pls_mask('I', idx, par);
  183. }
  184. static void cmd_mns_mask(const char type, int idx, char *par)
  185. {
  186. const char *cmd = (type == 'b' ? "ban" : type == 'e' ? "exempt" : "invite");
  187. if (!par[0]) {
  188. usage:
  189. dprintf(idx, "Usage: -%s <hostmask> [channel]\n", cmd);
  190. return;
  191. }
  192. int i = 0, j;
  193. struct chanset_t *chan = NULL;
  194. char s[UHOSTLEN] = "", *who = NULL, *chname = NULL, *mask = NULL;
  195. masklist *m = NULL;
  196. who = newsplit(&par);
  197. if (par[0] && strchr(CHANMETA, par[0]))
  198. chname = newsplit(&par);
  199. /* Did they mix up the two params? */
  200. if (!chname && strchr(CHANMETA, who[0])) {
  201. if (par[0]) {
  202. chname = who;
  203. who = newsplit(&par);
  204. } else {
  205. goto usage;
  206. }
  207. }
  208. if (!chname)
  209. chname = dcc[idx].u.chat->con_chan;
  210. if (chname || !(dcc[idx].user->flags & USER_MASTER)) {
  211. if (!chname)
  212. chname = dcc[idx].u.chat->con_chan;
  213. get_user_flagrec(dcc[idx].user, &user, chname);
  214. if (strchr(CHANMETA, chname[0]) && privchan(user, findchan_by_dname(chname), PRIV_OP)) {
  215. dprintf(idx, "No such channel.\n");
  216. return;
  217. }
  218. if (!chk_op(user, findchan_by_dname(chname)))
  219. return;
  220. }
  221. strlcpy(s, who, sizeof s);
  222. i = u_delmask(type, NULL, s, (dcc[idx].user->flags & USER_MASTER));
  223. if (i > 0) {
  224. if (lastdeletedmask)
  225. mask = lastdeletedmask;
  226. else
  227. mask = s;
  228. putlog(LOG_CMDS, "*", "#%s# -%s %s", dcc[idx].nick, cmd, mask);
  229. dprintf(idx, "%s %s: %s\n", "Removed", cmd, s);
  230. if (!conf.bot->hub) {
  231. for (chan = chanset; chan != NULL; chan = chan->next)
  232. add_mode(chan, '-', type, mask);
  233. } else
  234. write_userfile(idx);
  235. return;
  236. }
  237. /* Channel-specific ban? */
  238. if (chname)
  239. chan = findchan_by_dname(chname);
  240. if (chan) {
  241. m = type == 'b' ? chan->channel.ban : type == 'e' ? chan->channel.exempt : chan->channel.invite;
  242. if (str_isdigit(who) && (i = atoi(who)) > 0) {
  243. simple_snprintf(s, sizeof s, "%d", i);
  244. j = u_delmask(type, chan, s, 1);
  245. if (j > 0) {
  246. if (lastdeletedmask)
  247. mask = lastdeletedmask;
  248. else
  249. mask = s;
  250. putlog(LOG_CMDS, "*", "#%s# (%s) -%s %s", dcc[idx].nick, chan->dname, cmd, mask);
  251. dprintf(idx, "Removed %s channel %s: %s\n", chan->dname, cmd, mask);
  252. if (!conf.bot->hub)
  253. add_mode(chan, '-', type, mask);
  254. else
  255. write_userfile(idx);
  256. return;
  257. }
  258. i = 0;
  259. for (; m && m->mask && m->mask[0]; m = m->next) {
  260. if ((!u_equals_mask(type == 'b' ? global_bans : type == 'e' ? global_exempts :
  261. global_invites, m->mask)) &&
  262. (!u_equals_mask(type == 'b' ? chan->bans : type == 'e' ? chan->exempts :
  263. chan->invites, m->mask))) {
  264. i++;
  265. if (i == -j) {
  266. dprintf(idx, "%s %s '%s' on %s.\n", "Removed", cmd, m->mask, chan->dname);
  267. putlog(LOG_CMDS, "*", "#%s# (%s) -%s %s [on channel]", dcc[idx].nick, chan->dname, cmd, who);
  268. if (!conf.bot->hub)
  269. add_mode(chan, '-', type, m->mask);
  270. else
  271. write_userfile(idx);
  272. return;
  273. }
  274. }
  275. }
  276. } else {
  277. j = u_delmask(type, chan, who, 1);
  278. if (j > 0) {
  279. putlog(LOG_CMDS, "*", "#%s# (%s) -%s %s", dcc[idx].nick, dcc[idx].u.chat->con_chan, cmd, who);
  280. dprintf(idx, "Removed %s channel %s: %s\n", chname, cmd, who);
  281. if (!conf.bot->hub)
  282. add_mode(chan, '-', type, who);
  283. else
  284. write_userfile(idx);
  285. return;
  286. }
  287. for (; m && m->mask && m->mask[0]; m = m->next) {
  288. if (!rfc_casecmp(m->mask, who)) {
  289. dprintf(idx, "%s %s '%s' on %s.\n", "Removed", cmd, m->mask, chan->dname);
  290. putlog(LOG_CMDS, "*", "#%s# (%s) -%s %s [on channel]", dcc[idx].nick, chan->dname, cmd, who);
  291. if (!conf.bot->hub)
  292. add_mode(chan, '-', type, m->mask);
  293. else
  294. write_userfile(idx);
  295. return;
  296. }
  297. }
  298. }
  299. }
  300. dprintf(idx, "No such %s.\n", cmd);
  301. }
  302. static void cmd_mns_ban(int idx, char *par)
  303. {
  304. cmd_mns_mask('b', idx, par);
  305. }
  306. static void cmd_mns_exempt(int idx, char *par)
  307. {
  308. cmd_mns_mask('e', idx, par);
  309. }
  310. static void cmd_mns_invite(int idx, char *par)
  311. {
  312. cmd_mns_mask('I', idx, par);
  313. }
  314. static void cmd_masks(const char type, int idx, char *par)
  315. {
  316. const char *str_type = (type == 'b' ? "ban" : type == 'e' ? "exempt" : "invite");
  317. if (!strcasecmp(par, "all")) {
  318. putlog(LOG_CMDS, "*", "#%s# %ss all", dcc[idx].nick, str_type);
  319. tell_masks(type, idx, 1, "");
  320. } else if (!strcasecmp(par, "global")) {
  321. putlog(LOG_CMDS, "*", "#%s# %ss global", dcc[idx].nick, str_type);
  322. tell_masks(type, idx, 1, "", 1);
  323. } else {
  324. putlog(LOG_CMDS, "*", "#%s# %ss %s", dcc[idx].nick, str_type, par);
  325. tell_masks(type, idx, 0, par);
  326. }
  327. }
  328. static void cmd_bans(int idx, char *par)
  329. {
  330. cmd_masks('b', idx, par);
  331. }
  332. static void cmd_exempts(int idx, char *par)
  333. {
  334. cmd_masks('e', idx, par);
  335. }
  336. static void cmd_invites(int idx, char *par)
  337. {
  338. cmd_masks('I', idx, par);
  339. }
  340. static void cmd_info(int idx, char *par)
  341. {
  342. if (!use_info) {
  343. dprintf(idx, "Info storage is turned off.\n");
  344. return;
  345. }
  346. char s[512] = "", *chname = NULL, *s1 = (char *) get_user(&USERENTRY_INFO, dcc[idx].user);
  347. bool locked = 0;
  348. if (s1 && s1[0] == '@')
  349. locked = 1;
  350. if (par[0] && strchr(CHANMETA, par[0])) {
  351. chname = newsplit(&par);
  352. if (!findchan_by_dname(chname)) {
  353. dprintf(idx, "No such channel.\n");
  354. return;
  355. }
  356. get_handle_chaninfo(dcc[idx].nick, chname, s);
  357. if (s[0] == '@')
  358. locked = 1;
  359. s1 = s;
  360. } else
  361. chname = 0;
  362. if (!par[0]) {
  363. if (s1 && s1[0] == '@')
  364. s1++;
  365. if (s1 && s1[0]) {
  366. if (chname) {
  367. dprintf(idx, "Info on %s: %s\n", chname, s1);
  368. dprintf(idx, "Use 'info %s none' to remove it.\n", chname);
  369. } else {
  370. dprintf(idx, "Default info: %s\n", s1);
  371. dprintf(idx, "Use 'info none' to remove it.\n");
  372. }
  373. } else
  374. dprintf(idx, "No info has been set for you.\n");
  375. putlog(LOG_CMDS, "*", "#%s# info %s", dcc[idx].nick, chname ? chname : "");
  376. return;
  377. }
  378. if (locked && !(dcc[idx].user && (dcc[idx].user->flags & USER_MASTER))) {
  379. dprintf(idx, "Your info line is locked. Sorry.\n");
  380. return;
  381. }
  382. if (!strcasecmp(par, "none")) {
  383. if (chname) {
  384. par[0] = 0;
  385. set_handle_chaninfo(userlist, dcc[idx].nick, chname, NULL);
  386. dprintf(idx, "Removed your info line on %s.\n", chname);
  387. putlog(LOG_CMDS, "*", "#%s# info %s none", dcc[idx].nick, chname);
  388. } else {
  389. set_user(&USERENTRY_INFO, dcc[idx].user, NULL);
  390. dprintf(idx, "Removed your default info line.\n");
  391. putlog(LOG_CMDS, "*", "#%s# info none", dcc[idx].nick);
  392. }
  393. return;
  394. }
  395. /* if (par[0] == '@') This is stupid, and prevents a users info from being locked */
  396. /* par++; without .tcl, or a tcl script, aka, 'half-assed' -poptix 4Jun01 */
  397. if (chname) {
  398. set_handle_chaninfo(userlist, dcc[idx].nick, chname, par);
  399. dprintf(idx, "Your info on %s is now: %s\n", chname, par);
  400. putlog(LOG_CMDS, "*", "#%s# info %s ...", dcc[idx].nick, chname);
  401. } else {
  402. set_user(&USERENTRY_INFO, dcc[idx].user, par);
  403. dprintf(idx, "Your default info is now: %s\n", par);
  404. putlog(LOG_CMDS, "*", "#%s# info ...", dcc[idx].nick);
  405. }
  406. }
  407. static void cmd_chinfo(int idx, char *par)
  408. {
  409. if (!use_info) {
  410. dprintf(idx, "Info storage is turned off.\n");
  411. return;
  412. }
  413. char *handle = newsplit(&par);
  414. if (!handle[0]) {
  415. dprintf(idx, "Usage: chinfo <handle> [channel] <new-info>\n");
  416. return;
  417. }
  418. struct userrec *u1 = get_user_by_handle(userlist, handle);
  419. if (!u1 || (u1 && !whois_access(dcc[idx].user, u1))) {
  420. dprintf(idx, "No such user.\n");
  421. return;
  422. }
  423. char *chname = NULL;
  424. if (par[0] && strchr(CHANMETA, par[0])) {
  425. chname = newsplit(&par);
  426. if (!findchan_by_dname(chname)) {
  427. dprintf(idx, "No such channel.\n");
  428. return;
  429. }
  430. } else
  431. chname = 0;
  432. if (u1->bot && !(dcc[idx].user->flags & USER_MASTER)) {
  433. dprintf(idx, "You have to be master to change bots info.\n");
  434. return;
  435. }
  436. if ((u1->flags & USER_OWNER) && !(dcc[idx].user->flags & USER_OWNER)) {
  437. dprintf(idx, "You can't change info for the bot owner.\n");
  438. return;
  439. }
  440. if (chname) {
  441. get_user_flagrec(dcc[idx].user, &user, chname);
  442. get_user_flagrec(u1, &victim, chname);
  443. if ((chan_owner(victim) || glob_owner(victim)) &&
  444. !(glob_owner(user) || chan_owner(user))) {
  445. dprintf(idx, "You can't change info for the channel owner.\n");
  446. return;
  447. }
  448. }
  449. putlog(LOG_CMDS, "*", "#%s# chinfo %s %s %s", dcc[idx].nick, handle, chname ? chname : par, chname ? par : "");
  450. if (!strcasecmp(par, "none"))
  451. par[0] = 0;
  452. if (chname) {
  453. set_handle_chaninfo(userlist, handle, chname, par);
  454. if (par[0] == '@')
  455. dprintf(idx, "New info (LOCKED) for %s on %s: %s\n", handle, chname,
  456. &par[1]);
  457. else if (par[0])
  458. dprintf(idx, "New info for %s on %s: %s\n", handle, chname, par);
  459. else
  460. dprintf(idx, "Wiped info for %s on %s\n", handle, chname);
  461. if (conf.bot->hub)
  462. write_userfile(idx);
  463. } else {
  464. set_user(&USERENTRY_INFO, u1, par[0] ? par : NULL);
  465. if (par[0] == '@')
  466. dprintf(idx, "New default info (LOCKED) for %s: %s\n", handle, &par[1]);
  467. else if (par[0])
  468. dprintf(idx, "New default info for %s: %s\n", handle, par);
  469. else
  470. dprintf(idx, "Wiped default info for %s\n", handle);
  471. if (conf.bot->hub)
  472. write_userfile(idx);
  473. }
  474. }
  475. static void cmd_checkchannels(int idx, char *par)
  476. {
  477. putlog(LOG_CMDS, "*", "#%s# checkchannels", dcc[idx].nick);
  478. botnet_send_cmd_broad(-1, conf.bot->nick, dcc[idx].nick, idx, "chans");
  479. }
  480. static void cmd_slowjoin(int idx, char *par)
  481. {
  482. int intvl = 0, delay = 0, count = 0;
  483. char *chname = NULL, *p = NULL, buf[2048] = "", buf2[RESULT_LEN] = "";
  484. struct chanset_t *chan = NULL;
  485. tand_t *bot = NULL;
  486. /* slowjoin #chan 60 */
  487. putlog(LOG_CMDS, "*", "#%s# slowjoin %s", dcc[idx].nick, par);
  488. chname = newsplit(&par);
  489. p = newsplit(&par);
  490. intvl = atoi(p);
  491. if (!chname[0] || !p[0]) {
  492. dprintf(idx, "Usage: slowjoin <channel> <interval-seconds> [channel options]\n");
  493. return;
  494. }
  495. if (intvl < 10) {
  496. dprintf(idx, "Interval must be at least 10 seconds\n");
  497. return;
  498. }
  499. if ((chan = findchan_by_dname(chname))) {
  500. dprintf(idx, "Already on %s\n", chan->dname);
  501. return;
  502. }
  503. if (!strchr(CHANMETA, chname[0])) {
  504. dprintf(idx, "Invalid channel name\n");
  505. return;
  506. }
  507. simple_snprintf(buf, sizeof(buf), "+inactive addedby %s addedts %li", dcc[idx].nick, (long)now);
  508. if (par[0])
  509. strlcat(buf, par, sizeof(buf));
  510. if (channel_add(buf2, chname, buf) == ERROR) {
  511. dprintf(idx, "Invalid channel or channel options.\n");
  512. if (buf2[0])
  513. dprintf(idx, " %s\n", buf2);
  514. return;
  515. }
  516. buf2[0] = 0;
  517. chan = findchan_by_dname(chname);
  518. if (!chan) {
  519. dprintf(idx, "Hmmm... Channel didn't get added. Weird *shrug*\n");
  520. return;
  521. }
  522. simple_snprintf(buf2, sizeof(buf2), "cjoin %s %s", chan->dname, buf);
  523. putallbots(buf2);
  524. if (conf.bot->hub)
  525. count = 0;
  526. chan->status &= ~CHAN_INACTIVE;
  527. for (bot = tandbot; bot; bot = bot->next) {
  528. char tmp[100] = "";
  529. tmp[0] = 0;
  530. if (bot->u) {
  531. if (bot_hublevel(bot->u) < 999) {
  532. simple_snprintf(tmp, sizeof(tmp), "sj %s 0", chname);
  533. } else {
  534. struct flag_record fr = { FR_CHAN|FR_GLOBAL|FR_BOT, 0, 0, 0 };
  535. get_user_flagrec(bot->u, &fr, chname);
  536. /* Only send the 'sj' command if the bot is supposed to be in the channel (backups and such) */
  537. if (bot_shouldjoin(bot->u, &fr, chan, 1)) {
  538. /* Variation: 60 secs intvl should be 60 +/- 15 */
  539. int v = (random() % (intvl / 2)) - (intvl / 4);
  540. delay += intvl;
  541. simple_snprintf(tmp, sizeof(tmp), "sj %s %i", chname, delay + v);
  542. count++;
  543. }
  544. }
  545. if (tmp[0])
  546. putbot(bot->bot, tmp);
  547. }
  548. }
  549. if (!conf.bot->hub && shouldjoin(chan))
  550. count++;
  551. dprintf(idx, "%i bots joining %s during the next %i seconds\n", count, chan->dname, delay);
  552. if (!conf.bot->hub && shouldjoin(chan))
  553. join_chan(chan);
  554. }
  555. static void cmd_slowpart(int idx, char *par)
  556. {
  557. int intvl = 0, delay = 0, count = 1;
  558. char *chname = NULL, *p = NULL;
  559. struct chanset_t *chan = NULL;
  560. tand_t *bot = NULL;
  561. /* slowpart #chan 60 */
  562. putlog(LOG_CMDS, "*", "#%s# slowpart %s", dcc[idx].nick, par);
  563. chname = newsplit(&par);
  564. p = newsplit(&par);
  565. intvl = atoi(p);
  566. if (!chname[0] || !p[0]) {
  567. dprintf(idx, "Usage: slowpart <channel> <interval-seconds>\n");
  568. return;
  569. }
  570. if (intvl < 10) {
  571. dprintf(idx, "Interval must be at least 10 seconds\n");
  572. return;
  573. }
  574. if (!(chan = findchan_by_dname(chname))) {
  575. dprintf(idx, "No such channel %s\n", chname);
  576. return;
  577. }
  578. if (conf.bot->hub)
  579. count = 0;
  580. for (bot = tandbot; bot; bot = bot->next) {
  581. char tmp[100] = "";
  582. tmp[0] = 0;
  583. if (bot->u) {
  584. if (bot_hublevel(bot->u) < 999) { /* HUB */
  585. simple_snprintf(tmp, sizeof(tmp), "sp %s 0", chname);
  586. } else { /* LEAF */
  587. struct flag_record fr = { FR_CHAN|FR_GLOBAL|FR_BOT, 0, 0, 0 };
  588. get_user_flagrec(bot->u, &fr, chname);
  589. /* Only send the 'sp' command if the bot is supposed to be in the channel (backups and such) */
  590. if (bot_shouldjoin(bot->u, &fr, chan)) {
  591. /* Variation: 60 secs intvl should be 60 +/- 15 */
  592. int v = (random() % (intvl / 2)) - (intvl / 4);
  593. delay += intvl;
  594. simple_snprintf(tmp, sizeof(tmp), "sp %s %i", chname, delay + v);
  595. count++;
  596. }
  597. }
  598. if (tmp[0])
  599. putbot(bot->bot, tmp);
  600. }
  601. }
  602. remove_channel(chan);
  603. if (conf.bot->hub)
  604. write_userfile(-1);
  605. dprintf(idx, "Channel %s removed from the bot.\n", chname);
  606. dprintf(idx, "This includes any channel specific bans, invites, exemptions and user records that you set.\n");
  607. if (findchan_by_dname(chname)) {
  608. dprintf(idx, "Failed to remove channel.\n");
  609. return;
  610. }
  611. dprintf(idx, "%i bots parting %s during the next %i seconds\n", count, chname, delay);
  612. if (!conf.bot->hub)
  613. dprintf(DP_MODE, "PART %s\n", chname);
  614. }
  615. static void cmd_stick_yn(int idx, char *par, int yn)
  616. {
  617. int i = 0, j;
  618. struct chanset_t *chan = NULL;
  619. char *stick_type = NULL, s[UHOSTLEN] = "", chname[81] = "", type = 0, *str_type = NULL;
  620. maskrec *channel_list = NULL;
  621. stick_type = newsplit(&par);
  622. strlcpy(s, newsplit(&par), sizeof s);
  623. strlcpy(chname, newsplit(&par), sizeof chname);
  624. if (strcasecmp(stick_type, "exempt") &&
  625. strcasecmp(stick_type, "invite") &&
  626. strcasecmp(stick_type, "ban")) {
  627. strlcpy(chname, s, sizeof chname);
  628. strlcpy(s, stick_type, sizeof s);
  629. stick_type = "ban";
  630. }
  631. if (!s[0]) {
  632. dprintf(idx, "Usage: %sstick [ban/exempt/invite] <hostmask or number> [channel]\n", yn ? "" : "un");
  633. return;
  634. }
  635. /* Now deal with exemptions */
  636. if (!strcasecmp(stick_type, "exempt")) {
  637. type = 'e';
  638. str_type = "exempt";
  639. } else if (!strcasecmp(stick_type, "invite")) {
  640. type = 'I';
  641. str_type = "invite";
  642. } else if (!strcasecmp(stick_type, "ban")) {
  643. type = 'b';
  644. str_type = "ban";
  645. } else
  646. return;
  647. if (!chname[0]) {
  648. channel_list = (type == 'b' ? global_bans : type == 'e' ? global_exempts : global_invites);
  649. i = u_setsticky_mask(NULL, channel_list, s, (dcc[idx].user->flags & USER_MASTER) ? yn : -1, type);
  650. if (i > 0) {
  651. putlog(LOG_CMDS, "*", "#%s# %sstick %s %s", dcc[idx].nick, yn ? "" : "un", str_type, s);
  652. dprintf(idx, "%stuck %s: %s\n", yn ? "S" : "Uns", str_type, s);
  653. if (!conf.bot->hub) {
  654. struct chanset_t *achan = NULL;
  655. for (achan = chanset; achan != NULL; achan = achan->next)
  656. check_this_mask(type, achan, s, yn);
  657. } else
  658. write_userfile(idx);
  659. return;
  660. }
  661. strlcpy(chname, dcc[idx].u.chat->con_chan, sizeof chname);
  662. }
  663. /* Channel-specific mask? */
  664. if (!(chan = findchan_by_dname(chname))) {
  665. dprintf(idx, "No such channel.\n");
  666. return;
  667. }
  668. get_user_flagrec(dcc[idx].user, &user, chan->dname);
  669. if (privchan(user, chan, PRIV_OP)) {
  670. dprintf(idx, "No such channel.\n");
  671. return;
  672. }
  673. channel_list = (type == 'b' ? chan->bans : type == 'e' ? chan->exempts : chan->invites);
  674. if (str_isdigit(s)) {
  675. /* substract the numer of global masks to get the number of the channel masks */
  676. j = atoi(s);
  677. j -= count_mask(type == 'b' ? global_bans : type == 'e' ? global_exempts : global_invites);
  678. simple_snprintf(s, sizeof s, "%d", j);
  679. }
  680. j = u_setsticky_mask(chan, channel_list, s, yn, type);
  681. if (j > 0) {
  682. putlog(LOG_CMDS, "*", "#%s# %sstick %s %s %s", dcc[idx].nick, yn ? "" : "un", str_type, s, chname);
  683. dprintf(idx, "%stuck %s %s: %s\n", yn ? "S" : "Uns", chname, str_type, s);
  684. if (!conf.bot->hub)
  685. check_this_mask(type, chan, s, yn);
  686. else
  687. write_userfile(idx);
  688. return;
  689. }
  690. dprintf(idx, "No such %s.\n", str_type);
  691. }
  692. static void cmd_stick(int idx, char *par)
  693. {
  694. cmd_stick_yn(idx, par, 1);
  695. }
  696. static void cmd_unstick(int idx, char *par)
  697. {
  698. cmd_stick_yn(idx, par, 0);
  699. }
  700. static void cmd_pls_chrec(int idx, char *par)
  701. {
  702. char *nick = NULL, *chn = NULL;
  703. struct chanset_t *chan = NULL;
  704. struct userrec *u1 = NULL;
  705. struct chanuserrec *chanrec = NULL;
  706. if (!par[0]) {
  707. dprintf(idx, "Usage: +chrec <user> [channel]\n");
  708. return;
  709. }
  710. nick = newsplit(&par);
  711. u1 = get_user_by_handle(userlist, nick);
  712. if (!u1) {
  713. dprintf(idx, "No such user.\n");
  714. return;
  715. }
  716. if (!par[0])
  717. chan = findchan_by_dname(dcc[idx].u.chat->con_chan);
  718. else {
  719. chn = newsplit(&par);
  720. chan = findchan_by_dname(chn);
  721. }
  722. if (!chan) {
  723. dprintf(idx, "No such channel.\n");
  724. return;
  725. }
  726. get_user_flagrec(dcc[idx].user, &user, chan->dname);
  727. get_user_flagrec(u1, &victim, chan->dname);
  728. if (privchan(user, chan, PRIV_OP)) {
  729. dprintf(idx, "No such channel.\n");
  730. return;
  731. }
  732. if ((!glob_master(user) && !chan_master(user)) || /* drummer */
  733. (chan_owner(victim) && !chan_owner(user) && !glob_owner(user)) ||
  734. (glob_owner(victim) && !glob_owner(user))) {
  735. dprintf(idx, "You have no permission to do that.\n");
  736. return;
  737. }
  738. chanrec = get_chanrec(u1, chan->dname);
  739. if (chanrec) {
  740. dprintf(idx, "User %s already has a channel record for %s.\n",
  741. nick, chan->dname);
  742. return;
  743. }
  744. putlog(LOG_CMDS, "*", "#%s# +chrec %s %s", dcc[idx].nick, nick, chan->dname);
  745. add_chanrec(u1, chan->dname);
  746. dprintf(idx, "Added %s channel record for %s.\n", chan->dname, nick);
  747. if (conf.bot->hub)
  748. write_userfile(idx);
  749. }
  750. static void cmd_mns_chrec(int idx, char *par)
  751. {
  752. char *nick = NULL, *chn = NULL;
  753. struct userrec *u1 = NULL;
  754. struct chanuserrec *chanrec = NULL;
  755. if (!par[0]) {
  756. dprintf(idx, "Usage: -chrec <user> [channel]\n");
  757. return;
  758. }
  759. nick = newsplit(&par);
  760. u1 = get_user_by_handle(userlist, nick);
  761. if (!u1) {
  762. dprintf(idx, "No such user.\n");
  763. return;
  764. }
  765. if (!par[0]) {
  766. struct chanset_t *chan;
  767. chan = findchan_by_dname(dcc[idx].u.chat->con_chan);
  768. if (chan)
  769. chn = chan->dname;
  770. else {
  771. dprintf(idx, "Invalid console channel.\n");
  772. return;
  773. }
  774. } else
  775. chn = newsplit(&par);
  776. get_user_flagrec(dcc[idx].user, &user, chn);
  777. get_user_flagrec(u1, &victim, chn);
  778. if (privchan(user, findchan_by_dname(chn), PRIV_OP)) {
  779. dprintf(idx, "No such channel.\n");
  780. return;
  781. }
  782. if ((!glob_master(user) && !chan_master(user)) || /* drummer */
  783. (chan_owner(victim) && !chan_owner(user) && !glob_owner(user)) ||
  784. (glob_owner(victim) && !glob_owner(user))) {
  785. dprintf(idx, "You have no permission to do that.\n");
  786. return;
  787. }
  788. chanrec = get_chanrec(u1, chn);
  789. if (!chanrec) {
  790. dprintf(idx, "User %s doesn't have a channel record for %s.\n", nick, chn);
  791. return;
  792. }
  793. putlog(LOG_CMDS, "*", "#%s# -chrec %s %s", dcc[idx].nick, nick, chn);
  794. del_chanrec(u1, chn);
  795. dprintf(idx, "Removed %s channel record from %s.\n", chn, nick);
  796. if (conf.bot->hub)
  797. write_userfile(idx);
  798. }
  799. static void cmd_cycle(int idx, char *par)
  800. {
  801. char *chname = NULL;
  802. int delay = 10;
  803. struct chanset_t *chan = NULL;
  804. putlog(LOG_CMDS, "*", "#%s# cycle %s", dcc[idx].nick, par);
  805. if (!par[0]) {
  806. dprintf(idx, "Usage: cycle [%s]<channel> [delay]\n", CHANMETA);
  807. dprintf(idx, "rejoin delay defaults to '10'\n");
  808. return;
  809. }
  810. chname = newsplit(&par);
  811. chan = findchan_by_dname(chname);
  812. if (!chan) {
  813. dprintf(idx, "%s is not a valid channel.\n", chname);
  814. return;
  815. }
  816. if (par[0])
  817. delay = atoi(newsplit(&par));
  818. if (conf.bot->hub) {
  819. char buf2[201] = "";
  820. simple_snprintf(buf2, sizeof(buf2), "cycle %s %d", chname, delay); /* this just makes the bot PART */
  821. putallbots(buf2);
  822. } else {
  823. do_chanset(NULL, chan, "+inactive", DO_LOCAL);
  824. dprintf(DP_SERVER, "PART %s\n", chan->name);
  825. chan->channel.jointime = ((now + delay) - server_lag);
  826. }
  827. dprintf(idx, "Cycling %s for %d seconds.\n", chan->dname, delay);
  828. }
  829. static void cmd_down(int idx, char *par)
  830. {
  831. char *chname = NULL, buf2[201] = "";
  832. struct chanset_t *chan = NULL;
  833. putlog(LOG_CMDS, "*", "#%s# down %s", dcc[idx].nick, par);
  834. if (!par[0]) {
  835. dprintf(idx, "Usage: down [%s]<channel>\n", CHANMETA);
  836. return;
  837. }
  838. chname = newsplit(&par);
  839. chan = findchan_by_dname(chname);
  840. if (!chan) {
  841. dprintf(idx, "%s is not a valid channel.\n", chname);
  842. return;
  843. }
  844. simple_snprintf(buf2, sizeof(buf2), "down %s", chan->dname);
  845. putallbots(buf2);
  846. if (!conf.bot->hub) {
  847. add_mode(chan, '-', 'o', botname);
  848. chan->channel.no_op = (now + 10);
  849. }
  850. }
  851. static void pls_chan(int idx, char *par, char *bot)
  852. {
  853. char *chname = NULL, result[RESULT_LEN] = "", buf[2048] = "";
  854. struct chanset_t *chan = NULL;
  855. if (!bot)
  856. putlog(LOG_CMDS, "*", "#%s# +chan %s", dcc[idx].nick, par);
  857. if (!par[0]) {
  858. dprintf(idx, "Usage: +chan [%s]<channel> [options]\n", CHANMETA);
  859. return;
  860. }
  861. chname = newsplit(&par);
  862. simple_snprintf(buf, sizeof(buf), "cjoin %s %s", chname, bot ? bot : "*"); /* +chan makes all bots join */
  863. if (par[0]) {
  864. strlcat(buf, " ", sizeof(buf));
  865. strlcat(buf, par, sizeof(buf));
  866. strlcat(buf, " ", sizeof(buf));
  867. }
  868. if (!bot && findchan_by_dname(chname)) {
  869. dprintf(idx, "That channel already exists!\n");
  870. return;
  871. } else if ((chan = findchan(chname)) && !bot) {
  872. dprintf(idx, "That channel already exists as %s!\n", chan->dname);
  873. return;
  874. } else if (strchr(CHANMETA, chname[0]) == NULL) {
  875. dprintf(idx, "Invalid channel prefix.\n");
  876. return;
  877. } else if (strchr(chname, ',') != NULL) {
  878. dprintf(idx, "Invalid channel name.\n");
  879. return;
  880. }
  881. if (!chan && !findchan_by_dname(chname) && channel_add(result, chname, par) == ERROR) {
  882. dprintf(idx, "Invalid channel or channel options.\n");
  883. if (result[0])
  884. dprintf(idx, " %s\n", result);
  885. } else {
  886. if ((chan = findchan_by_dname(chname))) {
  887. char tmp[51] = "";
  888. simple_snprintf(tmp, sizeof(tmp), "addedby %s addedts %li", dcc[idx].nick, (long) now);
  889. if (buf[0]) {
  890. strlcat(buf, " ", sizeof(buf));
  891. strlcat(buf, tmp, sizeof(buf));
  892. }
  893. do_chanset(NULL, chan, buf[0] ? buf : tmp, DO_LOCAL);
  894. if (!bot) {
  895. dprintf(idx, "Channel %s added to the botnet.\n", chname);
  896. } else {
  897. dprintf(idx, "Channel %s added to the bot: %s\n", chname, bot);
  898. }
  899. putallbots(buf);
  900. }
  901. if (conf.bot->hub)
  902. write_userfile(-1);
  903. }
  904. }
  905. static void cmd_pls_chan(int idx, char *par)
  906. {
  907. pls_chan(idx, par, NULL);
  908. }
  909. static void cmd_botjoin(int idx, char *par)
  910. {
  911. char *bot = NULL;
  912. struct userrec *botu = NULL;
  913. putlog(LOG_CMDS, "*", "#%s# botjoin %s", dcc[idx].nick, par);
  914. if (!par[0]) {
  915. dprintf(idx, "Usage: botjoin <bot> [%s]<channel> [options]\n", CHANMETA);
  916. return;
  917. }
  918. bot = newsplit(&par);
  919. botu = get_user_by_handle(userlist, bot);
  920. if (botu && botu->bot) {
  921. pls_chan(idx, par, bot);
  922. } else {
  923. dprintf(idx, "Error: '%s' is not a bot.\n", bot);
  924. }
  925. dprintf(idx, "!!!! Warning: botjoin is an unfinished feature which will pretty much make all bots join the channel.\n");
  926. dprintf(idx, "!!!! Warning: You should probably -chan the channel now to avoid problems/confusion later.\n");
  927. }
  928. static void mns_chan(int idx, char *par, char *bot)
  929. {
  930. char *chname = NULL, buf2[1024] = "";
  931. struct chanset_t *chan = NULL;
  932. int i;
  933. if (!bot)
  934. putlog(LOG_CMDS, "*", "#%s# -chan %s", dcc[idx].nick, par);
  935. if (!par[0]) {
  936. dprintf(idx, "Usage: -chan [%s]<channel>\n", CHANMETA);
  937. return;
  938. }
  939. chname = newsplit(&par);
  940. simple_snprintf(buf2, sizeof(buf2), "cpart %s %s", chname, bot ? bot : "*");
  941. if (bot) /* bot will just set it +inactive */
  942. putbot(bot, buf2);
  943. else
  944. putallbots(buf2);
  945. chan = findchan_by_dname(chname);
  946. if (!chan) {
  947. if ((chan = findchan(chname)))
  948. dprintf(idx, "That channel exists with a short name of %s, use that.\n", chan->dname);
  949. else
  950. dprintf(idx, "That channel doesn't exist!\n");
  951. return;
  952. }
  953. if (!bot) {
  954. for (i = 0; i < dcc_total; i++) {
  955. if (dcc[i].type && (dcc[i].type->flags & DCT_CHAT) &&
  956. !rfc_casecmp(dcc[i].u.chat->con_chan, chan->dname)) {
  957. dprintf(i, "%s is no longer a valid channel, changing your console to '*'\n", chname);
  958. strlcpy(dcc[i].u.chat->con_chan, "*", 2);
  959. console_dostore(i, 0);
  960. }
  961. }
  962. remove_channel(chan);
  963. if (conf.bot->hub)
  964. write_userfile(idx);
  965. dprintf(idx, "Channel %s removed from the botnet.\n", chname);
  966. dprintf(idx, "This includes any channel specific bans, invites, exemptions and user records that you set.\n");
  967. } else
  968. dprintf(idx, "Channel %s removed from the bot: %s\n", chname, bot);
  969. }
  970. static void cmd_mns_chan(int idx, char *par)
  971. {
  972. mns_chan(idx, par, NULL);
  973. }
  974. static void cmd_botpart(int idx, char *par)
  975. {
  976. char *bot = NULL;
  977. struct userrec *botu = NULL;
  978. putlog(LOG_CMDS, "*", "#%s# botpart %s", dcc[idx].nick, par);
  979. if (!par[0]) {
  980. dprintf(idx, "Usage: botpart <bot> [%s]<channel> [options]\n", CHANMETA);
  981. return;
  982. }
  983. bot = newsplit(&par);
  984. botu = get_user_by_handle(userlist, bot);
  985. if (botu && botu->bot) {
  986. mns_chan(idx, par, bot);
  987. } else {
  988. dprintf(idx, "Error: '%s' is not a bot.\n", bot);
  989. }
  990. }
  991. /* thanks Excelsior */
  992. #define FLAG_COLS 4
  993. static void show_flag(int idx, char *work, int *cnt, const char *name, unsigned int state, size_t worksiz)
  994. {
  995. char tmp[101] = "", chr_state[15] = "";
  996. /* empty buffer if no (char *) name */
  997. if (((*cnt) < (FLAG_COLS - 1)) && (!name || (name && !name[0]))) (*cnt) = (FLAG_COLS - 1);
  998. (*cnt)++;
  999. if (*cnt > FLAG_COLS) {
  1000. *cnt = 1;
  1001. work[0] = 0;
  1002. }
  1003. if (!work[0])
  1004. strlcpy(work, " ", worksiz);
  1005. if (name && name[0]) {
  1006. chr_state[0] = 0;
  1007. if (state) {
  1008. strlcat(chr_state, GREEN(idx), sizeof(chr_state));
  1009. strlcat(chr_state, "+", sizeof(chr_state));
  1010. } else {
  1011. strlcat(chr_state, RED(idx), sizeof(chr_state));
  1012. strlcat(chr_state, "-", sizeof(chr_state));
  1013. }
  1014. strlcat(chr_state, COLOR_END(idx), sizeof(chr_state));
  1015. simple_snprintf(tmp, sizeof tmp, "%s%-17s", chr_state, name);
  1016. strlcat(work, tmp, worksiz);
  1017. }
  1018. if (*cnt >= FLAG_COLS)
  1019. dprintf(idx, "%s\n", work);
  1020. }
  1021. #define INT_COLS 1
  1022. static void show_int(int idx, char *work, int *cnt, const char *desc, int state, const char *yes, const char *no, size_t worksiz)
  1023. {
  1024. char tmp[101] = "", chr_state[101] = "";
  1025. simple_snprintf(chr_state, sizeof chr_state, "%d", state);
  1026. /* empty buffer if no (char *) name */
  1027. if (((*cnt) < (INT_COLS - 1)) && (!desc || (desc && !desc[0]))) (*cnt) = (INT_COLS - 1);
  1028. (*cnt)++;
  1029. if (*cnt > INT_COLS) {
  1030. *cnt = 1;
  1031. work[0] = 0;
  1032. }
  1033. if (!work[0])
  1034. strlcpy(work, " ", 3);
  1035. /* need to make next line all one char, and then put it into %-30s */
  1036. if (desc && desc[0]) {
  1037. char tmp2[50] = "", tmp3[50] = "";
  1038. strlcat(tmp2, BOLD(idx), sizeof(tmp2));
  1039. if (state && yes) {
  1040. strlcat(tmp2, yes, sizeof(tmp2));
  1041. strlcat(tmp3, " (", sizeof(tmp3));
  1042. strlcat(tmp3, chr_state, sizeof(tmp3));
  1043. strlcat(tmp3, ")", sizeof(tmp3));
  1044. } else if (!state && no) {
  1045. strlcat(tmp2, no, sizeof(tmp2));
  1046. strlcat(tmp3, " (", sizeof(tmp3));
  1047. strlcat(tmp3, chr_state, sizeof(tmp3));
  1048. strlcat(tmp3, ")", sizeof(tmp3));
  1049. } else if ((state && !yes) || (!state && !no)) {
  1050. strlcat(tmp2, chr_state, sizeof(tmp2));
  1051. }
  1052. strlcat(tmp2, BOLD_END(idx), sizeof(tmp2));
  1053. simple_snprintf(tmp, sizeof tmp, "%-30s %-20s %s", desc, tmp2, tmp3[0] ? tmp3 : "");
  1054. strlcat(work, tmp, worksiz);
  1055. }
  1056. if (*cnt >= INT_COLS)
  1057. dprintf(idx, "%s\n", work);
  1058. }
  1059. #define SHOW_FLAG(name, state) show_flag(idx, work, &cnt, name, state, sizeof(work))
  1060. #define SHOW_INT(desc, state, yes, no) show_int(idx, work, &cnt, desc, state, yes, no, sizeof(work))
  1061. #define P_STR deflag == P_KICK ? "Kick" : (deflag == P_DEOP ? "Deop" : (deflag == P_DELETE ? "Remove" : NULL))
  1062. #define F_STR(x) x == CHAN_FLAG_OP ? "Op" : (x == CHAN_FLAG_VOICE ? "Voice" : (x == CHAN_FLAG_USER ? "User" : NULL))
  1063. static void cmd_chaninfo(int idx, char *par)
  1064. {
  1065. char *chname = NULL, work[512] = "";
  1066. struct chanset_t *chan = NULL;
  1067. int cnt = 0;
  1068. if (!par[0]) {
  1069. chname = dcc[idx].u.chat->con_chan;
  1070. if (chname[0] == '*') {
  1071. dprintf(idx, "Your console channel is invalid.\n");
  1072. return;
  1073. }
  1074. } else {
  1075. chname = newsplit(&par);
  1076. get_user_flagrec(dcc[idx].user, &user, chname);
  1077. if (!glob_master(user) && !chan_master(user)) {
  1078. dprintf(idx, "You don't have access to %s.\n", chname);
  1079. return;
  1080. }
  1081. }
  1082. if (!strcasecmp(chname, "default"))
  1083. chan = chanset_default;
  1084. else
  1085. chan = findchan_by_dname(chname);
  1086. if (!chan || (chan && privchan(user, chan, PRIV_OP))) {
  1087. dprintf(idx, "No such channel.\n");
  1088. return;
  1089. } else {
  1090. char nick[HANDLEN + 1] = "", date[81] = "";
  1091. int deflag = 0;
  1092. if (chan->added_ts) {
  1093. strftime(date, sizeof date, "%c %Z", gmtime(&(chan->added_ts)));
  1094. } else
  1095. date[0] = 0;
  1096. if (chan->added_by && chan->added_by[0])
  1097. strlcpy(nick, chan->added_by, sizeof(nick));
  1098. else
  1099. nick[0] = 0;
  1100. putlog(LOG_CMDS, "*", "#%s# chaninfo %s", dcc[idx].nick, chname);
  1101. if (nick[0] && date[0])
  1102. dprintf(idx, "Settings for channel %s (Added %s by %s%s%s):\n", chan->dname, date, BOLD(idx), nick, BOLD_END(idx));
  1103. else
  1104. dprintf(idx, "Settings for channel %s:\n", chan->dname);
  1105. /* FIXME: SHOW_CHAR() here */
  1106. get_mode_protect(chan, work, sizeof(work));
  1107. dprintf(idx, "Protect modes (chanmode): %s\n", work[0] ? work : "None");
  1108. // dprintf(idx, "Protect topic (topic) : %s\n", chan->topic[0] ? chan->topic : "");
  1109. /* Chanchar template
  1110. * dprintf(idx, "String temp: %s\n", chan->temp[0] ? chan->temp : "NULL");
  1111. */
  1112. dprintf(idx, "Channel flags:\n");
  1113. work[0] = 0;
  1114. SHOW_FLAG("autoop", channel_autoop(chan));
  1115. SHOW_FLAG("backup", channel_backup(chan));
  1116. SHOW_FLAG("bitch", channel_bitch(chan));
  1117. SHOW_FLAG("botbitch", channel_botbitch(chan));
  1118. SHOW_FLAG("closed", channel_closed(chan));
  1119. SHOW_FLAG("cycle", channel_cycle(chan));
  1120. SHOW_FLAG("enforcebans", channel_enforcebans(chan));
  1121. SHOW_FLAG("fastop", channel_fastop(chan));
  1122. SHOW_FLAG("inactive", channel_inactive(chan));
  1123. SHOW_FLAG("meankicks", channel_meankicks(chan));
  1124. SHOW_FLAG("nodesynch", channel_nodesynch(chan));
  1125. SHOW_FLAG("nomassjoin", channel_nomassjoin(chan));
  1126. SHOW_FLAG("private", channel_privchan(chan));
  1127. SHOW_FLAG("protect", channel_protect(chan));
  1128. SHOW_FLAG("rbl", channel_rbl(chan));
  1129. // SHOW_FLAG("revengebot", channel_revengebot(chan));
  1130. // SHOW_FLAG("revenge", channel_revenge(chan));
  1131. if (HAVE_TAKE)
  1132. SHOW_FLAG("take", channel_take(chan));
  1133. SHOW_FLAG("voice", channel_voice(chan));
  1134. SHOW_FLAG("voicebitch", channel_voicebitch(chan));
  1135. SHOW_FLAG("", 0);
  1136. SHOW_FLAG("dynamicbans", channel_dynamicbans(chan));
  1137. SHOW_FLAG("userbans", !channel_nouserbans(chan));
  1138. SHOW_FLAG("dynamicexempts", channel_dynamicexempts(chan));
  1139. SHOW_FLAG("userexempts", !channel_nouserexempts(chan));
  1140. SHOW_FLAG("dynamicinvites", channel_dynamicinvites(chan));
  1141. SHOW_FLAG("userinvites", !channel_nouserinvites(chan));
  1142. SHOW_FLAG("", 0);
  1143. work[0] = 0;
  1144. /* Chanflag template
  1145. * SHOW_FLAG("template", channel_template(chan));
  1146. * also include %ctemp in dprintf.
  1147. */
  1148. work[0] = cnt = 0;
  1149. /* Chanint template
  1150. * SHOW_INT("Desc: ", integer, "YES", "NO");
  1151. */
  1152. dprintf(idx, "Channel settings:\n");
  1153. deflag = chan->bad_cookie;
  1154. SHOW_INT("Auto-delay: ", chan->auto_delay, NULL, "None");
  1155. SHOW_INT("Bad-cookie:" , chan->bad_cookie, P_STR, "Ignore");
  1156. SHOW_INT("Ban-time: ", chan->ban_time, NULL, "Forever");
  1157. SHOW_INT("Ban-type: ", chan->ban_type, NULL, "3");
  1158. SHOW_INT("Closed-ban: ", chan->closed_ban, NULL, "Don't!");
  1159. SHOW_INT("Closed-invite:", chan->closed_invite, NULL, "Don't!");
  1160. SHOW_INT("Closed-Private:", chan->closed_private, NULL, "Don't!");
  1161. SHOW_INT("Exempt-time: ", chan->exempt_time, NULL, "Forever");
  1162. SHOW_INT("Flood-exempt: ", chan->flood_exempt_mode, F_STR(chan->flood_exempt_mode), "None");
  1163. SHOW_INT("Flood-lock-time: ", chan->flood_lock_time, NULL, "Don't");
  1164. SHOW_INT("Invite-time: ", chan->invite_time, NULL, "Forever");
  1165. SHOW_INT("Knock: ", chan->knock_flags, F_STR(chan->knock_flags), "None");
  1166. SHOW_INT("Limit raise (limit): ", chan->limitraise, NULL, "Disabled");
  1167. deflag = chan->manop;
  1168. SHOW_INT("Manop: ", chan->manop, P_STR, "Ignore");
  1169. deflag = chan->mdop;
  1170. SHOW_INT("Mdop: ", chan->mdop, P_STR, "Ignore");
  1171. deflag = chan->mop;
  1172. SHOW_INT("Mop: ", chan->mop, P_STR, "Ignore");
  1173. // SHOW_INT("Revenge-mode: ", chan->revenge_mode, NULL, NULL);
  1174. SHOW_INT("Protect-backup: ", chan->protect_backup, "Do!", "Don't!");
  1175. SHOW_INT("Voice-non-ident: ", chan->voice_non_ident, "Do!", "Don't!");
  1176. dprintf(idx, "Flood settings: chan ctcp join kick deop nick mjoin\n");
  1177. dprintf(idx, " number: %3d %3d %3d %3d %3d %3d %3d\n",
  1178. chan->flood_pub_thr, chan->flood_ctcp_thr,
  1179. chan->flood_join_thr, chan->flood_kick_thr,
  1180. chan->flood_deop_thr, chan->flood_nick_thr,
  1181. chan->flood_mjoin_thr);
  1182. dprintf(idx, " time : %3u %3u %3u %3u %3u %3u %3u\n",
  1183. chan->flood_pub_time, chan->flood_ctcp_time,
  1184. chan->flood_join_time, chan->flood_kick_time,
  1185. chan->flood_deop_time, chan->flood_nick_time,
  1186. chan->flood_mjoin_time);
  1187. }
  1188. }
  1189. static void cmd_chanset(int idx, char *par)
  1190. {
  1191. char *chname = NULL, result[RESULT_LEN] = "";
  1192. struct chanset_t *chan = NULL;
  1193. int all = 0;
  1194. if (!par[0]) {
  1195. putlog(LOG_CMDS, "*", "#%s# chanset %s", dcc[idx].nick, par);
  1196. dprintf(idx, "Usage: chanset [%schannel|*|default] <settings>\n", CHANMETA);
  1197. return;
  1198. }
  1199. // Determine channel name
  1200. if (strchr(CHANMETA, par[0]) || !strncasecmp(par, "default", 7) || !strncmp(par, "*", 1))
  1201. chname = newsplit(&par);
  1202. else {
  1203. if (strncmp(dcc[idx].u.chat->con_chan, "*", 1) && !(chan = findchan_by_dname(chname = dcc[idx].u.chat->con_chan))) {
  1204. dprintf(idx, "Invalid console channel.\n");
  1205. return;
  1206. }
  1207. chname = dcc[idx].u.chat->con_chan;
  1208. }
  1209. if (chname && chname[0]) {
  1210. if (!strncmp(chname, "*", 1)) {
  1211. all = 1;
  1212. get_user_flagrec(dcc[idx].user, &user, chanset ? chanset->dname : "");
  1213. if (!glob_owner(user)) {
  1214. dprintf(idx, "You need to be a global owner to use '%schanset *'.\n", (dcc[idx].u.chat->channel >= 0) ? settings.dcc_prefix : "");
  1215. return;
  1216. }
  1217. } else if (!strcasecmp(chname, "default")) {
  1218. chan = chanset_default;
  1219. } else
  1220. chan = findchan_by_dname(chname);
  1221. }
  1222. if (!all && !chan && chname && chname[0]) {
  1223. dprintf(idx, "No such channel.\n");
  1224. return;
  1225. }
  1226. if (!par[0]) {
  1227. dprintf(idx, "Usage: chanset [%schannel|*|default] <settings>\n", CHANMETA);
  1228. return;
  1229. }
  1230. if (!all) {
  1231. get_user_flagrec(dcc[idx].user, &user, chan->dname);
  1232. if (privchan(user, chan, PRIV_OP)) {
  1233. dprintf(idx, "No such channel.\n");
  1234. return;
  1235. }
  1236. if (!glob_master(user) && !chan_master(user)) {
  1237. dprintf(idx, "You don't have access to %s. \n", chan->dname);
  1238. return;
  1239. } else if ((strstr(par, "+private") || strstr(par, "-private")) && (!glob_owner(user))) {
  1240. dprintf(idx, "You don't have access to set +/-private on %s (halting command).\n", chan->dname);
  1241. return;
  1242. } else if ((strstr(par, "+backup") || strstr(par, "-backup")) && (!glob_owner(user))) {
  1243. dprintf(idx, "You don't have access to set +/-backup on %s (halting command).\n", chan->dname);
  1244. return;
  1245. } else if ((strstr(par, "+inactive") || strstr(par, "-inactive")) && (!glob_owner(user))) {
  1246. dprintf(idx, "You don't have access to set +/-inactive on %s (halting command).\n", chan->dname);
  1247. return;
  1248. }
  1249. }
  1250. putlog(LOG_CMDS, "*", "#%s# chanset (%s) %s", dcc[idx].nick, all ? "*" : chan->dname, par);
  1251. if (do_chanset(result, all ? NULL : chan, par, DO_LOCAL | DO_NET | CMD) == ERROR) {
  1252. dprintf(idx, "Error trying to set { %s } on %s: %s\n", par, all ? "all channels" : chan->dname, result);
  1253. return;
  1254. }
  1255. if (all)
  1256. dprintf(idx, "Successfully set modes { %s } on all channels (Including the default).\n", par);
  1257. else
  1258. dprintf(idx, "Successfully set modes { %s } on %s\n", par, chan->dname);
  1259. if (conf.bot->hub)
  1260. write_userfile(idx);
  1261. }
  1262. /* DCC CHAT COMMANDS
  1263. *
  1264. * Function call should be:
  1265. * int cmd_whatever(idx,"parameters");
  1266. *
  1267. * NOTE: As with msg commands, the function is responsible for any logging.
  1268. */
  1269. static cmd_t C_dcc_channels[] =
  1270. {
  1271. {"+ban", "o|o", (Function) cmd_pls_ban, NULL, AUTH},
  1272. {"+exempt", "o|o", (Function) cmd_pls_exempt, NULL, AUTH},
  1273. {"+invite", "o|o", (Function) cmd_pls_invite, NULL, AUTH},
  1274. {"+chan", "n", (Function) cmd_pls_chan, NULL, 0},
  1275. {"+chrec", "m|m", (Function) cmd_pls_chrec, NULL, 0},
  1276. {"-ban", "o|o", (Function) cmd_mns_ban, NULL, AUTH},
  1277. {"-chan", "n", (Function) cmd_mns_chan, NULL, 0},
  1278. {"-chrec", "m|m", (Function) cmd_mns_chrec, NULL, 0},
  1279. {"-exempt", "o|o", (Function) cmd_mns_exempt, NULL, AUTH},
  1280. {"-invite", "o|o", (Function) cmd_mns_invite, NULL, AUTH},
  1281. {"bans", "o|o", (Function) cmd_bans, NULL, 0},
  1282. {"botjoin", "n", (Function) cmd_botjoin, NULL, 0},
  1283. {"botpart", "n", (Function) cmd_botpart, NULL, 0},
  1284. {"exempts", "o|o", (Function) cmd_exempts, NULL, 0},
  1285. {"invites", "o|o", (Function) cmd_invites, NULL, 0},
  1286. {"chaninfo", "m|m", (Function) cmd_chaninfo, NULL, 0},
  1287. {"chanset", "m|m", (Function) cmd_chanset, NULL, 0},
  1288. {"chinfo", "m|m", (Function) cmd_chinfo, NULL, 0},
  1289. {"cycle", "n|n", (Function) cmd_cycle, NULL, AUTH},
  1290. {"down", "n|n", (Function) cmd_down, NULL, AUTH},
  1291. {"info", "", (Function) cmd_info, NULL, 0},
  1292. {"checkchannels", "n", (Function) cmd_checkchannels, NULL, HUB},
  1293. {"slowjoin", "n", (Function) cmd_slowjoin, NULL, 0},
  1294. {"slowpart", "n|n", (Function) cmd_slowpart, NULL, 0},
  1295. {"stick", "o|o", (Function) cmd_stick, NULL, AUTH},
  1296. {"unstick", "o|o", (Function) cmd_unstick, NULL, AUTH},
  1297. {NULL, NULL, NULL, NULL, 0}
  1298. };