irc-mode.c 30 KB

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