irc-mode.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * Please read the file COPYING, README and AUTHORS for more information.
  10. */
  11. #include "portab.h"
  12. /**
  13. * @file
  14. * IRC commands for mode changes (like MODE, AWAY, etc.)
  15. */
  16. #include "imp.h"
  17. #include <assert.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "defines.h"
  22. #include "conn.h"
  23. #include "channel.h"
  24. #include "irc-write.h"
  25. #include "lists.h"
  26. #include "log.h"
  27. #include "parse.h"
  28. #include "messages.h"
  29. #include "conf.h"
  30. #include "exp.h"
  31. #include "irc-mode.h"
  32. static bool Client_Mode PARAMS((CLIENT *Client, REQUEST *Req, CLIENT *Origin,
  33. CLIENT *Target));
  34. static bool Channel_Mode PARAMS((CLIENT *Client, REQUEST *Req, CLIENT *Origin,
  35. CHANNEL *Channel));
  36. static bool Add_To_List PARAMS((char what, CLIENT *Prefix, CLIENT *Client,
  37. CHANNEL *Channel, const char *Pattern));
  38. static bool Del_From_List PARAMS((char what, CLIENT *Prefix, CLIENT *Client,
  39. CHANNEL *Channel, const char *Pattern));
  40. static bool Send_ListChange PARAMS((const bool IsAdd, const char ModeChar,
  41. CLIENT *Prefix, CLIENT *Client,
  42. CHANNEL *Channel, const char *Mask));
  43. /**
  44. * Handler for the IRC "MODE" command.
  45. *
  46. * See RFC 2812 section 3.1.5 ("user mode message") and section 3.2.3
  47. * ("channel mode message"), and RFC 2811 section 4 ("channel modes").
  48. *
  49. * @param Client The client from which this command has been received.
  50. * @param Req Request structure with prefix and all parameters.
  51. * @returns CONNECTED or DISCONNECTED.
  52. */
  53. GLOBAL bool
  54. IRC_MODE( CLIENT *Client, REQUEST *Req )
  55. {
  56. CLIENT *cl, *origin;
  57. CHANNEL *chan;
  58. assert(Client != NULL);
  59. assert(Req != NULL);
  60. /* No parameters? */
  61. if (Req->argc < 1)
  62. return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
  63. Client_ID(Client), Req->command);
  64. /* Origin for answers */
  65. if (Client_Type(Client) == CLIENT_SERVER) {
  66. origin = Client_Search(Req->prefix);
  67. if (!origin)
  68. return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
  69. Client_ID(Client),
  70. Req->prefix);
  71. } else
  72. origin = Client;
  73. /* Channel or user mode? */
  74. cl = NULL; chan = NULL;
  75. if (Client_IsValidNick(Req->argv[0]))
  76. cl = Client_Search(Req->argv[0]);
  77. if (Channel_IsValidName(Req->argv[0]))
  78. chan = Channel_Search(Req->argv[0]);
  79. if (cl)
  80. return Client_Mode(Client, Req, origin, cl);
  81. if (chan)
  82. return Channel_Mode(Client, Req, origin, chan);
  83. /* No target found! */
  84. return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
  85. Client_ID(Client), Req->argv[0]);
  86. } /* IRC_MODE */
  87. /**
  88. * Check if the "mode limit" for a client has been reached.
  89. *
  90. * This limit doesn't apply for servers or services!
  91. *
  92. * @param Client The client to check.
  93. * @param Count The number of modes already handled.
  94. * @return true if the limit has been reached.
  95. */
  96. static bool
  97. Mode_Limit_Reached(CLIENT *Client, int Count)
  98. {
  99. if (Client_Type(Client) == CLIENT_SERVER
  100. || Client_Type(Client) == CLIENT_SERVICE)
  101. return false;
  102. if (Count < MAX_HNDL_MODES_ARG)
  103. return false;
  104. return true;
  105. }
  106. /**
  107. * Handle client mode requests
  108. *
  109. * @param Client The client from which this command has been received.
  110. * @param Req Request structure with prefix and all parameters.
  111. * @param Origin The originator of the MODE command (prefix).
  112. * @param Target The target (client) of this MODE command.
  113. * @returns CONNECTED or DISCONNECTED.
  114. */
  115. static bool
  116. Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
  117. {
  118. char the_modes[COMMAND_LEN], x[2], *mode_ptr;
  119. bool ok, set;
  120. bool send_RPL_HOSTHIDDEN_MSG = false;
  121. int mode_arg;
  122. size_t len;
  123. /* Is the client allowed to request or change the modes? */
  124. if (Client_Type(Client) == CLIENT_USER) {
  125. /* Users are only allowed to manipulate their own modes! */
  126. if (Target != Client)
  127. return IRC_WriteStrClient(Client,
  128. ERR_USERSDONTMATCH_MSG,
  129. Client_ID(Client));
  130. }
  131. /* Mode request: let's answer it :-) */
  132. if (Req->argc == 1)
  133. return IRC_WriteStrClient(Origin, RPL_UMODEIS_MSG,
  134. Client_ID(Target),
  135. Client_Modes(Target));
  136. mode_arg = 1;
  137. mode_ptr = Req->argv[mode_arg];
  138. /* Initial state: set or unset modes? */
  139. if (*mode_ptr == '+') {
  140. set = true;
  141. strcpy(the_modes, "+");
  142. } else if (*mode_ptr == '-') {
  143. set = false;
  144. strcpy(the_modes, "-");
  145. } else
  146. return IRC_WriteStrClient(Origin, ERR_UMODEUNKNOWNFLAG_MSG,
  147. Client_ID(Origin));
  148. x[1] = '\0';
  149. ok = CONNECTED;
  150. while (mode_ptr) {
  151. mode_ptr++;
  152. if (!*mode_ptr) {
  153. /* Try next argument if there's any */
  154. mode_arg++;
  155. if (mode_arg < Req->argc)
  156. mode_ptr = Req->argv[mode_arg];
  157. else
  158. break;
  159. }
  160. switch(*mode_ptr) {
  161. case '+':
  162. case '-':
  163. if ((*mode_ptr == '+' && !set)
  164. || (*mode_ptr == '-' && set)) {
  165. /* Action modifier ("+"/"-") must be changed */
  166. len = strlen(the_modes) - 1;
  167. if (the_modes[len] == '+'
  168. || the_modes[len] == '-') {
  169. /* Last character in the "result
  170. * string" was an "action", so just
  171. * overwrite it with the new action */
  172. the_modes[len] = *mode_ptr;
  173. } else {
  174. /* Append new modifier character to
  175. * the resulting mode string */
  176. x[0] = *mode_ptr;
  177. strlcat(the_modes, x,
  178. sizeof(the_modes));
  179. }
  180. if (*mode_ptr == '+')
  181. set = true;
  182. else
  183. set = false;
  184. }
  185. continue;
  186. }
  187. /* Validate modes */
  188. x[0] = '\0';
  189. switch (*mode_ptr) {
  190. case 'b': /* Block private msgs */
  191. case 'C': /* Only messages from clients sharing a channel */
  192. case 'i': /* Invisible */
  193. case 's': /* Server messages */
  194. case 'w': /* Wallops messages */
  195. x[0] = *mode_ptr;
  196. break;
  197. case 'a': /* Away */
  198. if (Client_Type(Client) == CLIENT_SERVER) {
  199. x[0] = 'a';
  200. Client_SetAway(Origin, DEFAULT_AWAY_MSG);
  201. } else
  202. ok = IRC_WriteStrClient(Origin,
  203. ERR_NOPRIVILEGES_MSG,
  204. Client_ID(Origin));
  205. break;
  206. case 'B': /* Bot */
  207. if (Client_HasMode(Client, 'r'))
  208. ok = IRC_WriteStrClient(Origin,
  209. ERR_RESTRICTED_MSG,
  210. Client_ID(Origin));
  211. else
  212. x[0] = 'B';
  213. break;
  214. case 'c': /* Receive connect notices
  215. * (only settable by IRC operators!) */
  216. if (!set || Client_Type(Client) == CLIENT_SERVER
  217. || Client_OperByMe(Origin))
  218. x[0] = 'c';
  219. else
  220. ok = IRC_WriteStrClient(Origin,
  221. ERR_NOPRIVILEGES_MSG,
  222. Client_ID(Origin));
  223. break;
  224. case 'o': /* IRC operator (only unsettable!) */
  225. if (!set || Client_Type(Client) == CLIENT_SERVER) {
  226. Client_SetOperByMe(Target, false);
  227. x[0] = 'o';
  228. } else
  229. ok = IRC_WriteStrClient(Origin,
  230. ERR_NOPRIVILEGES_MSG,
  231. Client_ID(Origin));
  232. break;
  233. case 'q': /* KICK-protected user */
  234. if (!set || Client_Type(Client) == CLIENT_SERVER
  235. || Client_OperByMe(Origin))
  236. x[0] = 'q';
  237. else
  238. ok = IRC_WriteStrClient(Origin,
  239. ERR_NOPRIVILEGES_MSG,
  240. Client_ID(Origin));
  241. break;
  242. case 'r': /* Restricted (only settable) */
  243. if (set || Client_Type(Client) == CLIENT_SERVER)
  244. x[0] = 'r';
  245. else
  246. ok = IRC_WriteStrClient(Origin,
  247. ERR_RESTRICTED_MSG,
  248. Client_ID(Origin));
  249. break;
  250. case 'R': /* Registered (not [un]settable by clients) */
  251. if (Client_Type(Client) == CLIENT_SERVER)
  252. x[0] = 'R';
  253. else
  254. ok = IRC_WriteStrClient(Origin,
  255. ERR_NICKREGISTER_MSG,
  256. Client_ID(Origin));
  257. break;
  258. case 'x': /* Cloak hostname */
  259. if (Client_HasMode(Client, 'r'))
  260. ok = IRC_WriteStrClient(Origin,
  261. ERR_RESTRICTED_MSG,
  262. Client_ID(Origin));
  263. else if (!set || Conf_CloakHostModeX[0]
  264. || Client_Type(Client) == CLIENT_SERVER
  265. || Client_OperByMe(Client)) {
  266. x[0] = 'x';
  267. send_RPL_HOSTHIDDEN_MSG = true;
  268. } else
  269. ok = IRC_WriteStrClient(Origin,
  270. ERR_NOPRIVILEGES_MSG,
  271. Client_ID(Origin));
  272. break;
  273. default:
  274. if (Client_Type(Client) != CLIENT_SERVER) {
  275. Log(LOG_DEBUG,
  276. "Unknown mode \"%c%c\" from \"%s\"!?",
  277. set ? '+' : '-', *mode_ptr,
  278. Client_ID(Origin));
  279. ok = IRC_WriteStrClient(Origin,
  280. ERR_UMODEUNKNOWNFLAG2_MSG,
  281. Client_ID(Origin),
  282. set ? '+' : '-',
  283. *mode_ptr);
  284. x[0] = '\0';
  285. } else {
  286. Log(LOG_DEBUG,
  287. "Handling unknown mode \"%c%c\" from \"%s\" for \"%s\" ...",
  288. set ? '+' : '-', *mode_ptr,
  289. Client_ID(Origin), Client_ID(Target));
  290. x[0] = *mode_ptr;
  291. }
  292. }
  293. if (!ok)
  294. break;
  295. /* Is there a valid mode change? */
  296. if (!x[0])
  297. continue;
  298. if (set) {
  299. if (Client_ModeAdd(Target, x[0]))
  300. strlcat(the_modes, x, sizeof(the_modes));
  301. } else {
  302. if (Client_ModeDel(Target, x[0]))
  303. strlcat(the_modes, x, sizeof(the_modes));
  304. }
  305. }
  306. /* Are there changed modes? */
  307. if (the_modes[1]) {
  308. /* Remove needless action modifier characters */
  309. len = strlen(the_modes) - 1;
  310. if (the_modes[len] == '+' || the_modes[len] == '-')
  311. the_modes[len] = '\0';
  312. if (Client_Type(Client) == CLIENT_SERVER) {
  313. /* Forward modes to other servers */
  314. if (Client_Conn(Target) != NONE) {
  315. /* Remote server (service?) changed modes
  316. * for one of our clients. Inform it! */
  317. IRC_WriteStrClientPrefix(Target, Origin,
  318. "MODE %s :%s",
  319. Client_ID(Target),
  320. the_modes);
  321. }
  322. IRC_WriteStrServersPrefix(Client, Origin,
  323. "MODE %s :%s",
  324. Client_ID(Target),
  325. the_modes);
  326. } else {
  327. /* Send reply to client and inform other servers */
  328. ok = IRC_WriteStrClientPrefix(Client, Origin,
  329. "MODE %s :%s",
  330. Client_ID(Target),
  331. the_modes);
  332. IRC_WriteStrServersPrefix(Client, Origin,
  333. "MODE %s :%s",
  334. Client_ID(Target),
  335. the_modes);
  336. }
  337. if (send_RPL_HOSTHIDDEN_MSG && Client_Conn(Target) > NONE) {
  338. /* A new (cloaked) hostname must be annoucned */
  339. IRC_WriteStrClientPrefix(Target, Origin,
  340. RPL_HOSTHIDDEN_MSG,
  341. Client_ID(Target),
  342. Client_HostnameDisplayed(Target));
  343. }
  344. LogDebug("%s \"%s\": Mode change, now \"%s\".",
  345. Client_TypeText(Target), Client_Mask(Target),
  346. Client_Modes(Target));
  347. }
  348. IRC_SetPenalty(Client, 1);
  349. return ok;
  350. } /* Client_Mode */
  351. static bool
  352. Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel)
  353. {
  354. char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], argadd[CLIENT_PASS_LEN];
  355. const char *mode_ptr;
  356. /* Member or not? -- That's the question! */
  357. if (!Channel_IsMemberOf(Channel, Origin))
  358. return IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
  359. Client_ID(Origin), Channel_Name(Channel), Channel_Modes(Channel));
  360. /* The sender is a member: generate extended reply */
  361. strlcpy(the_modes, Channel_Modes(Channel), sizeof(the_modes));
  362. mode_ptr = the_modes;
  363. the_args[0] = '\0';
  364. while(*mode_ptr) {
  365. switch(*mode_ptr) {
  366. case 'l':
  367. snprintf(argadd, sizeof(argadd), " %lu", Channel_MaxUsers(Channel));
  368. strlcat(the_args, argadd, sizeof(the_args));
  369. break;
  370. case 'k':
  371. strlcat(the_args, " ", sizeof(the_args));
  372. strlcat(the_args, Channel_Key(Channel), sizeof(the_args));
  373. break;
  374. }
  375. mode_ptr++;
  376. }
  377. if (the_args[0])
  378. strlcat(the_modes, the_args, sizeof(the_modes));
  379. if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
  380. Client_ID(Origin), Channel_Name(Channel),
  381. the_modes))
  382. return DISCONNECTED;
  383. #ifndef STRICT_RFC
  384. if (!IRC_WriteStrClient(Origin, RPL_CREATIONTIME_MSG,
  385. Client_ID(Origin), Channel_Name(Channel),
  386. Channel_CreationTime(Channel)))
  387. return DISCONNECTED;
  388. #endif
  389. return CONNECTED;
  390. }
  391. /**
  392. * Handle channel mode and channel-user mode changes
  393. */
  394. static bool
  395. Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
  396. {
  397. char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2],
  398. argadd[CLIENT_PASS_LEN], *mode_ptr, *o_mode_ptr;
  399. bool connected, set, skiponce, retval, use_servermode,
  400. is_halfop, is_op, is_admin, is_owner, is_machine, is_oper;
  401. int mode_arg, arg_arg, mode_arg_count = 0;
  402. CLIENT *client;
  403. long l;
  404. size_t len;
  405. is_halfop = is_op = is_admin = is_owner = is_machine = is_oper = false;
  406. if (Channel_IsModeless(Channel))
  407. return IRC_WriteStrClient(Client, ERR_NOCHANMODES_MSG,
  408. Client_ID(Client), Channel_Name(Channel));
  409. /* Mode request: let's answer it :-) */
  410. if (Req->argc <= 1)
  411. return Channel_Mode_Answer_Request(Origin, Channel);
  412. /* Check if origin is oper and opers can use mode */
  413. use_servermode = Conf_OperServerMode;
  414. if(Client_OperByMe(Client) && Conf_OperCanMode) {
  415. is_oper = true;
  416. }
  417. /* Check if client is a server/service */
  418. if(Client_Type(Client) == CLIENT_SERVER ||
  419. Client_Type(Client) == CLIENT_SERVICE) {
  420. is_machine = true;
  421. }
  422. /* Check if client is member of channel or an oper or an server/service */
  423. if(!Channel_IsMemberOf(Channel, Client) && !is_oper && !is_machine)
  424. return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG,
  425. Client_ID(Origin),
  426. Channel_Name(Channel));
  427. mode_arg = 1;
  428. mode_ptr = Req->argv[mode_arg];
  429. if (Req->argc > mode_arg + 1)
  430. arg_arg = mode_arg + 1;
  431. else
  432. arg_arg = -1;
  433. /* Initial state: set or unset modes? */
  434. skiponce = false;
  435. switch (*mode_ptr) {
  436. case '-':
  437. set = false;
  438. break;
  439. case '+':
  440. set = true;
  441. break;
  442. default:
  443. set = true;
  444. skiponce = true;
  445. }
  446. /* Prepare reply string */
  447. strcpy(the_modes, set ? "+" : "-");
  448. the_args[0] = '\0';
  449. x[1] = '\0';
  450. connected = CONNECTED;
  451. while (mode_ptr) {
  452. if (!skiponce)
  453. mode_ptr++;
  454. if (!*mode_ptr) {
  455. /* Try next argument if there's any */
  456. if (arg_arg < 0)
  457. break;
  458. if (arg_arg > mode_arg)
  459. mode_arg = arg_arg;
  460. else
  461. mode_arg++;
  462. if (mode_arg >= Req->argc)
  463. break;
  464. mode_ptr = Req->argv[mode_arg];
  465. if (Req->argc > mode_arg + 1)
  466. arg_arg = mode_arg + 1;
  467. else
  468. arg_arg = -1;
  469. }
  470. skiponce = false;
  471. switch (*mode_ptr) {
  472. case '+':
  473. case '-':
  474. if (((*mode_ptr == '+') && !set)
  475. || ((*mode_ptr == '-') && set)) {
  476. /* Action modifier ("+"/"-") must be changed ... */
  477. len = strlen(the_modes) - 1;
  478. if (the_modes[len] == '+' || the_modes[len] == '-') {
  479. /* Adjust last action modifier in result */
  480. the_modes[len] = *mode_ptr;
  481. } else {
  482. /* Append modifier character to result string */
  483. x[0] = *mode_ptr;
  484. strlcat(the_modes, x, sizeof(the_modes));
  485. }
  486. set = *mode_ptr == '+';
  487. }
  488. continue;
  489. }
  490. /* Are there arguments left? */
  491. if (arg_arg >= Req->argc)
  492. arg_arg = -1;
  493. if(!is_machine && !is_oper) {
  494. o_mode_ptr = Channel_UserModes(Channel, Client);
  495. while( *o_mode_ptr ) {
  496. if ( *o_mode_ptr == 'q')
  497. is_owner = true;
  498. if ( *o_mode_ptr == 'a')
  499. is_admin = true;
  500. if ( *o_mode_ptr == 'o')
  501. is_op = true;
  502. if ( *o_mode_ptr == 'h')
  503. is_halfop = true;
  504. o_mode_ptr++;
  505. }
  506. }
  507. /* Validate modes */
  508. x[0] = '\0';
  509. argadd[0] = '\0';
  510. client = NULL;
  511. switch (*mode_ptr) {
  512. /* --- Channel modes --- */
  513. case 'R': /* Registered users only */
  514. case 's': /* Secret channel */
  515. case 'z': /* Secure connections only */
  516. if(!is_oper && !is_machine && !is_owner &&
  517. !is_admin && !is_op) {
  518. connected = IRC_WriteStrClient(Origin,
  519. ERR_CHANOPRIVSNEEDED_MSG,
  520. Client_ID(Origin), Channel_Name(Channel));
  521. goto chan_exit;
  522. }
  523. case 'i': /* Invite only */
  524. case 'V': /* Invite disallow */
  525. case 'M': /* Only identified nicks can write */
  526. case 'm': /* Moderated */
  527. case 'n': /* Only members can write */
  528. case 'Q': /* No kicks */
  529. case 't': /* Topic locked */
  530. if(is_oper || is_machine || is_owner ||
  531. is_admin || is_op || is_halfop)
  532. x[0] = *mode_ptr;
  533. else
  534. connected = IRC_WriteStrClient(Origin,
  535. ERR_CHANOPRIVSNEEDED_MSG,
  536. Client_ID(Origin), Channel_Name(Channel));
  537. break;
  538. case 'k': /* Channel key */
  539. if (Mode_Limit_Reached(Client, mode_arg_count++))
  540. goto chan_exit;
  541. if (!set) {
  542. if (is_oper || is_machine || is_owner ||
  543. is_admin || is_op || is_halfop)
  544. x[0] = *mode_ptr;
  545. else
  546. connected = IRC_WriteStrClient(Origin,
  547. ERR_CHANOPRIVSNEEDED_MSG,
  548. Client_ID(Origin),
  549. Channel_Name(Channel));
  550. break;
  551. }
  552. if (arg_arg > mode_arg) {
  553. if (is_oper || is_machine || is_owner ||
  554. is_admin || is_op || is_halfop) {
  555. Channel_ModeDel(Channel, 'k');
  556. Channel_SetKey(Channel,
  557. Req->argv[arg_arg]);
  558. strlcpy(argadd, Channel_Key(Channel),
  559. sizeof(argadd));
  560. x[0] = *mode_ptr;
  561. } else {
  562. connected = IRC_WriteStrClient(Origin,
  563. ERR_CHANOPRIVSNEEDED_MSG,
  564. Client_ID(Origin),
  565. Channel_Name(Channel));
  566. }
  567. Req->argv[arg_arg][0] = '\0';
  568. arg_arg++;
  569. } else {
  570. connected = IRC_WriteStrClient(Origin,
  571. ERR_NEEDMOREPARAMS_MSG,
  572. Client_ID(Origin), Req->command);
  573. goto chan_exit;
  574. }
  575. break;
  576. case 'l': /* Member limit */
  577. if (Mode_Limit_Reached(Client, mode_arg_count++))
  578. goto chan_exit;
  579. if (!set) {
  580. if (is_oper || is_machine || is_owner ||
  581. is_admin || is_op || is_halfop)
  582. x[0] = *mode_ptr;
  583. else
  584. connected = IRC_WriteStrClient(Origin,
  585. ERR_CHANOPRIVSNEEDED_MSG,
  586. Client_ID(Origin),
  587. Channel_Name(Channel));
  588. break;
  589. }
  590. if (arg_arg > mode_arg) {
  591. if (is_oper || is_machine || is_owner ||
  592. is_admin || is_op || is_halfop) {
  593. l = atol(Req->argv[arg_arg]);
  594. if (l > 0 && l < 0xFFFF) {
  595. Channel_ModeDel(Channel, 'l');
  596. Channel_SetMaxUsers(Channel, l);
  597. snprintf(argadd, sizeof(argadd),
  598. "%ld", l);
  599. x[0] = *mode_ptr;
  600. }
  601. } else {
  602. connected = IRC_WriteStrClient(Origin,
  603. ERR_CHANOPRIVSNEEDED_MSG,
  604. Client_ID(Origin),
  605. Channel_Name(Channel));
  606. }
  607. Req->argv[arg_arg][0] = '\0';
  608. arg_arg++;
  609. } else {
  610. connected = IRC_WriteStrClient(Origin,
  611. ERR_NEEDMOREPARAMS_MSG,
  612. Client_ID(Origin), Req->command);
  613. goto chan_exit;
  614. }
  615. break;
  616. case 'O': /* IRC operators only */
  617. if (set) {
  618. /* Only IRC operators are allowed to
  619. * set the 'O' channel mode! */
  620. if(is_oper || is_machine)
  621. x[0] = 'O';
  622. else
  623. connected = IRC_WriteStrClient(Origin,
  624. ERR_NOPRIVILEGES_MSG,
  625. Client_ID(Origin));
  626. } else if(is_oper || is_machine || is_owner ||
  627. is_admin || is_op)
  628. x[0] = 'O';
  629. else
  630. connected = IRC_WriteStrClient(Origin,
  631. ERR_CHANOPRIVSNEEDED_MSG,
  632. Client_ID(Origin),
  633. Channel_Name(Channel));
  634. break;
  635. case 'P': /* Persistent channel */
  636. if (set) {
  637. /* Only IRC operators are allowed to
  638. * set the 'P' channel mode! */
  639. if(is_oper || is_machine)
  640. x[0] = 'P';
  641. else
  642. connected = IRC_WriteStrClient(Origin,
  643. ERR_NOPRIVILEGES_MSG,
  644. Client_ID(Origin));
  645. } else if(is_oper || is_machine || is_owner ||
  646. is_admin || is_op)
  647. x[0] = 'P';
  648. else
  649. connected = IRC_WriteStrClient(Origin,
  650. ERR_CHANOPRIVSNEEDED_MSG,
  651. Client_ID(Origin),
  652. Channel_Name(Channel));
  653. break;
  654. /* --- Channel user modes --- */
  655. case 'q': /* Owner */
  656. case 'a': /* Channel admin */
  657. if(!is_oper && !is_machine && !is_owner && !is_admin) {
  658. connected = IRC_WriteStrClient(Origin,
  659. ERR_CHANOPPRIVTOOLOW_MSG,
  660. Client_ID(Origin),
  661. Channel_Name(Channel));
  662. goto chan_exit;
  663. }
  664. case 'o': /* Channel operator */
  665. if(!is_oper && !is_machine && !is_owner &&
  666. !is_admin && !is_op) {
  667. connected = IRC_WriteStrClient(Origin,
  668. ERR_CHANOPRIVSNEEDED_MSG,
  669. Client_ID(Origin),
  670. Channel_Name(Channel));
  671. goto chan_exit;
  672. }
  673. case 'h': /* Half Op */
  674. if(!is_oper && !is_machine && !is_owner &&
  675. !is_admin && !is_op) {
  676. connected = IRC_WriteStrClient(Origin,
  677. ERR_CHANOPRIVSNEEDED_MSG,
  678. Client_ID(Origin),
  679. Channel_Name(Channel));
  680. goto chan_exit;
  681. }
  682. case 'v': /* Voice */
  683. if (arg_arg > mode_arg) {
  684. if (is_oper || is_machine || is_owner ||
  685. is_admin || is_op || is_halfop) {
  686. client = Client_Search(Req->argv[arg_arg]);
  687. if (client)
  688. x[0] = *mode_ptr;
  689. else
  690. connected = IRC_WriteStrClient(Origin,
  691. ERR_NOSUCHNICK_MSG,
  692. Client_ID(Origin),
  693. Req->argv[arg_arg]);
  694. } else {
  695. connected = IRC_WriteStrClient(Origin,
  696. ERR_CHANOPRIVSNEEDED_MSG,
  697. Client_ID(Origin),
  698. Channel_Name(Channel));
  699. }
  700. Req->argv[arg_arg][0] = '\0';
  701. arg_arg++;
  702. } else {
  703. connected = IRC_WriteStrClient(Origin,
  704. ERR_NEEDMOREPARAMS_MSG,
  705. Client_ID(Origin), Req->command);
  706. goto chan_exit;
  707. }
  708. break;
  709. /* --- Channel lists --- */
  710. case 'I': /* Invite lists */
  711. case 'b': /* Ban lists */
  712. case 'e': /* Channel exception lists */
  713. if (Mode_Limit_Reached(Client, mode_arg_count++))
  714. goto chan_exit;
  715. if (arg_arg > mode_arg) {
  716. /* modify list */
  717. if (is_oper || is_machine || is_owner ||
  718. is_admin || is_op || is_halfop) {
  719. connected = set
  720. ? Add_To_List(*mode_ptr, Origin,
  721. Client, Channel,
  722. Req->argv[arg_arg])
  723. : Del_From_List(*mode_ptr, Origin,
  724. Client, Channel,
  725. Req->argv[arg_arg]);
  726. } else {
  727. connected = IRC_WriteStrClient(Origin,
  728. ERR_CHANOPRIVSNEEDED_MSG,
  729. Client_ID(Origin),
  730. Channel_Name(Channel));
  731. }
  732. Req->argv[arg_arg][0] = '\0';
  733. arg_arg++;
  734. } else {
  735. switch (*mode_ptr) {
  736. case 'I':
  737. Channel_ShowInvites(Origin, Channel);
  738. break;
  739. case 'b':
  740. Channel_ShowBans(Origin, Channel);
  741. break;
  742. case 'e':
  743. Channel_ShowExcepts(Origin, Channel);
  744. break;
  745. }
  746. }
  747. break;
  748. default:
  749. if (Client_Type(Client) != CLIENT_SERVER) {
  750. Log(LOG_DEBUG,
  751. "Unknown mode \"%c%c\" from \"%s\" on %s!?",
  752. set ? '+' : '-', *mode_ptr,
  753. Client_ID(Origin), Channel_Name(Channel));
  754. connected = IRC_WriteStrClient(Origin,
  755. ERR_UNKNOWNMODE_MSG,
  756. Client_ID(Origin), *mode_ptr,
  757. Channel_Name(Channel));
  758. x[0] = '\0';
  759. } else {
  760. Log(LOG_DEBUG,
  761. "Handling unknown mode \"%c%c\" from \"%s\" on %s ...",
  762. set ? '+' : '-', *mode_ptr,
  763. Client_ID(Origin), Channel_Name(Channel));
  764. x[0] = *mode_ptr;
  765. }
  766. }
  767. if (!connected)
  768. break;
  769. /* Is there a valid mode change? */
  770. if (!x[0])
  771. continue;
  772. /* Validate target client */
  773. if (client && (!Channel_IsMemberOf(Channel, client))) {
  774. if (!IRC_WriteStrClient
  775. (Origin, ERR_USERNOTINCHANNEL_MSG,
  776. Client_ID(Origin), Client_ID(client),
  777. Channel_Name(Channel)))
  778. break;
  779. continue;
  780. }
  781. if (client) {
  782. /* Channel-User-Mode */
  783. retval = set
  784. ? Channel_UserModeAdd(Channel, client, x[0])
  785. : Channel_UserModeDel(Channel, client, x[0]);
  786. if (retval) {
  787. strlcat(the_args, " ", sizeof(the_args));
  788. strlcat(the_args, Client_ID(client),
  789. sizeof(the_args));
  790. strlcat(the_modes, x, sizeof(the_modes));
  791. LogDebug
  792. ("User \"%s\": Mode change on %s, now \"%s\"",
  793. Client_Mask(client), Channel_Name(Channel),
  794. Channel_UserModes(Channel, client));
  795. }
  796. } else {
  797. /* Channel-Mode */
  798. retval = set
  799. ? Channel_ModeAdd(Channel, x[0])
  800. : Channel_ModeDel(Channel, x[0]);
  801. if (retval) {
  802. strlcat(the_modes, x, sizeof(the_modes));
  803. LogDebug("Channel %s: Mode change, now \"%s\".",
  804. Channel_Name(Channel),
  805. Channel_Modes(Channel));
  806. }
  807. }
  808. /* Are there additional arguments to add? */
  809. if (argadd[0]) {
  810. strlcat(the_args, " ", sizeof(the_args));
  811. strlcat(the_args, argadd, sizeof(the_args));
  812. }
  813. }
  814. chan_exit:
  815. /* Are there changed modes? */
  816. if (the_modes[1]) {
  817. /* Clean up mode string */
  818. len = strlen(the_modes) - 1;
  819. if ((the_modes[len] == '+') || (the_modes[len] == '-'))
  820. the_modes[len] = '\0';
  821. if (Client_Type(Client) == CLIENT_SERVER) {
  822. /* MODE requests for local channels from other servers
  823. * are definitely invalid! */
  824. if (Channel_IsLocal(Channel)) {
  825. Log(LOG_ALERT, "Got remote MODE command for local channel!? Ignored.");
  826. return CONNECTED;
  827. }
  828. /* Forward mode changes to channel users and all the
  829. * other remote servers: */
  830. IRC_WriteStrServersPrefix(Client, Origin,
  831. "MODE %s %s%s", Channel_Name(Channel),
  832. the_modes, the_args);
  833. IRC_WriteStrChannelPrefix(Client, Channel, Origin,
  834. false, "MODE %s %s%s", Channel_Name(Channel),
  835. the_modes, the_args);
  836. } else {
  837. if (use_servermode)
  838. Origin = Client_ThisServer();
  839. /* Send reply to client and inform other servers and channel users */
  840. connected = IRC_WriteStrClientPrefix(Client, Origin,
  841. "MODE %s %s%s", Channel_Name(Channel),
  842. the_modes, the_args);
  843. /* Only forward requests for non-local channels */
  844. if (!Channel_IsLocal(Channel))
  845. IRC_WriteStrServersPrefix(Client, Origin,
  846. "MODE %s %s%s", Channel_Name(Channel),
  847. the_modes, the_args);
  848. IRC_WriteStrChannelPrefix(Client, Channel, Origin,
  849. false, "MODE %s %s%s", Channel_Name(Channel),
  850. the_modes, the_args);
  851. }
  852. }
  853. IRC_SetPenalty(Client, 1);
  854. return connected;
  855. } /* Channel_Mode */
  856. GLOBAL bool
  857. IRC_AWAY( CLIENT *Client, REQUEST *Req )
  858. {
  859. assert( Client != NULL );
  860. assert( Req != NULL );
  861. if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  862. if(( Req->argc == 1 ) && (Req->argv[0][0] ))
  863. {
  864. Client_SetAway( Client, Req->argv[0] );
  865. Client_ModeAdd( Client, 'a' );
  866. IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
  867. return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
  868. }
  869. else
  870. {
  871. Client_ModeDel( Client, 'a' );
  872. IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
  873. return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
  874. }
  875. } /* IRC_AWAY */
  876. /**
  877. * Add entries to channel invite, ban and exception lists.
  878. *
  879. * @param what Can be 'I' for invite, 'b' for ban, and 'e' for exception list.
  880. * @param Prefix The originator of the command.
  881. * @param Client The sender of the command.
  882. * @param Channel The channel of which the list should be modified.
  883. * @param Pattern The pattern to add to the list.
  884. * @return CONNECTED or DISCONNECTED.
  885. */
  886. static bool
  887. Add_To_List(char what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel,
  888. const char *Pattern)
  889. {
  890. const char *mask;
  891. struct list_head *list = NULL;
  892. long int current_count;
  893. assert(Client != NULL);
  894. assert(Channel != NULL);
  895. assert(Pattern != NULL);
  896. assert(what == 'I' || what == 'b' || what == 'e');
  897. mask = Lists_MakeMask(Pattern);
  898. current_count = Lists_Count(Channel_GetListInvites(Channel))
  899. + Lists_Count(Channel_GetListExcepts(Channel))
  900. + Lists_Count(Channel_GetListBans(Channel));
  901. switch(what) {
  902. case 'I':
  903. list = Channel_GetListInvites(Channel);
  904. break;
  905. case 'b':
  906. list = Channel_GetListBans(Channel);
  907. break;
  908. case 'e':
  909. list = Channel_GetListExcepts(Channel);
  910. break;
  911. }
  912. if (Lists_CheckDupeMask(list, mask))
  913. return CONNECTED;
  914. if (Client_Type(Client) == CLIENT_USER &&
  915. current_count >= MAX_HNDL_CHANNEL_LISTS)
  916. return IRC_WriteStrClient(Client, ERR_LISTFULL_MSG,
  917. Client_ID(Client),
  918. Channel_Name(Channel), mask,
  919. MAX_HNDL_CHANNEL_LISTS);
  920. switch (what) {
  921. case 'I':
  922. if (!Channel_AddInvite(Channel, mask, false))
  923. return CONNECTED;
  924. break;
  925. case 'b':
  926. if (!Channel_AddBan(Channel, mask))
  927. return CONNECTED;
  928. break;
  929. case 'e':
  930. if (!Channel_AddExcept(Channel, mask))
  931. return CONNECTED;
  932. break;
  933. }
  934. return Send_ListChange(true, what, Prefix, Client, Channel, mask);
  935. }
  936. /**
  937. * Delete entries from channel invite, ban and exeption lists.
  938. *
  939. * @param what Can be 'I' for invite, 'b' for ban, and 'e' for exception list.
  940. * @param Prefix The originator of the command.
  941. * @param Client The sender of the command.
  942. * @param Channel The channel of which the list should be modified.
  943. * @param Pattern The pattern to add to the list.
  944. * @return CONNECTED or DISCONNECTED.
  945. */
  946. static bool
  947. Del_From_List(char what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel,
  948. const char *Pattern)
  949. {
  950. const char *mask;
  951. struct list_head *list = NULL;
  952. assert(Client != NULL);
  953. assert(Channel != NULL);
  954. assert(Pattern != NULL);
  955. assert(what == 'I' || what == 'b' || what == 'e');
  956. mask = Lists_MakeMask(Pattern);
  957. switch (what) {
  958. case 'I':
  959. list = Channel_GetListInvites(Channel);
  960. break;
  961. case 'b':
  962. list = Channel_GetListBans(Channel);
  963. break;
  964. case 'e':
  965. list = Channel_GetListExcepts(Channel);
  966. break;
  967. }
  968. if (!Lists_CheckDupeMask(list, mask))
  969. return CONNECTED;
  970. Lists_Del(list, mask);
  971. return Send_ListChange(false, what, Prefix, Client, Channel, mask);
  972. }
  973. /**
  974. * Send information about changed channel invite/ban/exception lists to clients.
  975. *
  976. * @param IsAdd true if the list item has been added, false otherwise.
  977. * @param ModeChar The mode to use (e. g. 'b' or 'I')
  978. * @param Prefix The originator of the mode list change.
  979. * @param Client The sender of the command.
  980. * @param Channel The channel of which the list has been modified.
  981. * @param Mask The mask which has been added or removed.
  982. * @return CONNECTED or DISCONNECTED.
  983. */
  984. static bool
  985. Send_ListChange(const bool IsAdd, const char ModeChar, CLIENT *Prefix,
  986. CLIENT *Client, CHANNEL *Channel, const char *Mask)
  987. {
  988. bool ok = true;
  989. /* Send confirmation to the client */
  990. if (Client_Type(Client) == CLIENT_USER)
  991. ok = IRC_WriteStrClientPrefix(Client, Prefix, "MODE %s %c%c %s",
  992. Channel_Name(Channel),
  993. IsAdd ? '+' : '-',
  994. ModeChar, Mask);
  995. /* to other servers */
  996. IRC_WriteStrServersPrefix(Client, Prefix, "MODE %s %c%c %s",
  997. Channel_Name(Channel), IsAdd ? '+' : '-',
  998. ModeChar, Mask);
  999. /* and local users in channel */
  1000. IRC_WriteStrChannelPrefix(Client, Channel, Prefix, false,
  1001. "MODE %s %c%c %s", Channel_Name(Channel),
  1002. IsAdd ? '+' : '-', ModeChar, Mask );
  1003. return ok;
  1004. } /* Send_ListChange */
  1005. /* -eof- */