irc-mode.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993
  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. int mode_arg;
  121. size_t len;
  122. /* Is the client allowed to request or change the modes? */
  123. if (Client_Type(Client) == CLIENT_USER) {
  124. /* Users are only allowed to manipulate their own modes! */
  125. if (Target != Client)
  126. return IRC_WriteStrClient(Client,
  127. ERR_USERSDONTMATCH_MSG,
  128. Client_ID(Client));
  129. }
  130. /* Mode request: let's answer it :-) */
  131. if (Req->argc == 1)
  132. return IRC_WriteStrClient(Origin, RPL_UMODEIS_MSG,
  133. Client_ID(Origin),
  134. Client_Modes(Target));
  135. mode_arg = 1;
  136. mode_ptr = Req->argv[mode_arg];
  137. /* Initial state: set or unset modes? */
  138. if (*mode_ptr == '+') {
  139. set = true;
  140. strcpy(the_modes, "+");
  141. } else if (*mode_ptr == '-') {
  142. set = false;
  143. strcpy(the_modes, "-");
  144. } else
  145. return IRC_WriteStrClient(Origin, ERR_UMODEUNKNOWNFLAG_MSG,
  146. Client_ID(Origin));
  147. x[1] = '\0';
  148. ok = CONNECTED;
  149. while (mode_ptr) {
  150. mode_ptr++;
  151. if (!*mode_ptr) {
  152. /* Try next argument if there's any */
  153. mode_arg++;
  154. if (mode_arg < Req->argc)
  155. mode_ptr = Req->argv[mode_arg];
  156. else
  157. break;
  158. }
  159. switch(*mode_ptr) {
  160. case '+':
  161. case '-':
  162. if ((*mode_ptr == '+' && !set)
  163. || (*mode_ptr == '-' && set)) {
  164. /* Action modifier ("+"/"-") must be changed */
  165. len = strlen(the_modes) - 1;
  166. if (the_modes[len] == '+'
  167. || the_modes[len] == '-') {
  168. /* Last character in the "result
  169. * string" was an "action", so just
  170. * overwrite it with the new action */
  171. the_modes[len] = *mode_ptr;
  172. } else {
  173. /* Append new modifier character to
  174. * the resulting mode string */
  175. x[0] = *mode_ptr;
  176. strlcat(the_modes, x,
  177. sizeof(the_modes));
  178. }
  179. if (*mode_ptr == '+')
  180. set = true;
  181. else
  182. set = false;
  183. }
  184. continue;
  185. }
  186. /* Validate modes */
  187. x[0] = '\0';
  188. switch (*mode_ptr) {
  189. case 'C': /* Only messages from clients sharing a channel */
  190. case 'i': /* Invisible */
  191. case 's': /* Server messages */
  192. case 'w': /* Wallops messages */
  193. x[0] = *mode_ptr;
  194. break;
  195. case 'a': /* Away */
  196. if (Client_Type(Client) == CLIENT_SERVER) {
  197. x[0] = 'a';
  198. Client_SetAway(Origin, DEFAULT_AWAY_MSG);
  199. } else
  200. ok = IRC_WriteStrClient(Origin,
  201. ERR_NOPRIVILEGES_MSG,
  202. Client_ID(Origin));
  203. break;
  204. case 'c': /* Receive connect notices
  205. * (only settable by IRC operators!) */
  206. if (!set || Client_Type(Client) == CLIENT_SERVER
  207. || Client_OperByMe(Origin))
  208. x[0] = 'c';
  209. else
  210. ok = IRC_WriteStrClient(Origin,
  211. ERR_NOPRIVILEGES_MSG,
  212. Client_ID(Origin));
  213. break;
  214. case 'o': /* IRC operator (only unsettable!) */
  215. if (!set || Client_Type(Client) == CLIENT_SERVER) {
  216. Client_SetOperByMe(Target, false);
  217. x[0] = 'o';
  218. } else
  219. ok = IRC_WriteStrClient(Origin,
  220. ERR_NOPRIVILEGES_MSG,
  221. Client_ID(Origin));
  222. break;
  223. case 'r': /* Restricted (only settable) */
  224. if (set || Client_Type(Client) == CLIENT_SERVER)
  225. x[0] = 'r';
  226. else
  227. ok = IRC_WriteStrClient(Origin,
  228. ERR_RESTRICTED_MSG,
  229. Client_ID(Origin));
  230. break;
  231. case 'x': /* Cloak hostname */
  232. if (Client_HasMode(Client, 'r'))
  233. ok = IRC_WriteStrClient(Origin,
  234. ERR_RESTRICTED_MSG,
  235. Client_ID(Origin));
  236. else
  237. x[0] = 'x';
  238. break;
  239. default:
  240. if (Client_Type(Client) != CLIENT_SERVER) {
  241. Log(LOG_DEBUG,
  242. "Unknown mode \"%c%c\" from \"%s\"!?",
  243. set ? '+' : '-', *mode_ptr,
  244. Client_ID(Origin));
  245. ok = IRC_WriteStrClient(Origin,
  246. ERR_UMODEUNKNOWNFLAG2_MSG,
  247. Client_ID(Origin),
  248. set ? '+' : '-',
  249. *mode_ptr);
  250. x[0] = '\0';
  251. } else {
  252. Log(LOG_DEBUG,
  253. "Handling unknown mode \"%c%c\" from \"%s\" for \"%s\" ...",
  254. set ? '+' : '-', *mode_ptr,
  255. Client_ID(Origin), Client_ID(Target));
  256. x[0] = *mode_ptr;
  257. }
  258. }
  259. if (!ok)
  260. break;
  261. /* Is there a valid mode change? */
  262. if (!x[0])
  263. continue;
  264. if (set) {
  265. if (Client_ModeAdd(Target, x[0]))
  266. strlcat(the_modes, x, sizeof(the_modes));
  267. } else {
  268. if (Client_ModeDel(Target, x[0]))
  269. strlcat(the_modes, x, sizeof(the_modes));
  270. }
  271. }
  272. /* Are there changed modes? */
  273. if (the_modes[1]) {
  274. /* Remove needless action modifier characters */
  275. len = strlen(the_modes) - 1;
  276. if (the_modes[len] == '+' || the_modes[len] == '-')
  277. the_modes[len] = '\0';
  278. if (Client_Type(Client) == CLIENT_SERVER) {
  279. /* Forward modes to other servers */
  280. if (Client_Conn(Target) != NONE) {
  281. /* Remote server (service?) changed modes
  282. * for one of our clients. Inform it! */
  283. IRC_WriteStrClientPrefix(Target, Origin,
  284. "MODE %s :%s",
  285. Client_ID(Target),
  286. the_modes);
  287. }
  288. IRC_WriteStrServersPrefix(Client, Origin,
  289. "MODE %s :%s",
  290. Client_ID(Target),
  291. the_modes);
  292. } else {
  293. /* Send reply to client and inform other servers */
  294. ok = IRC_WriteStrClientPrefix(Client, Origin,
  295. "MODE %s :%s",
  296. Client_ID(Target),
  297. the_modes);
  298. IRC_WriteStrServersPrefix(Client, Origin,
  299. "MODE %s :%s",
  300. Client_ID(Target),
  301. the_modes);
  302. }
  303. LogDebug("%s \"%s\": Mode change, now \"%s\".",
  304. Client_TypeText(Target), Client_Mask(Target),
  305. Client_Modes(Target));
  306. }
  307. IRC_SetPenalty(Client, 1);
  308. return ok;
  309. } /* Client_Mode */
  310. static bool
  311. Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel)
  312. {
  313. char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], argadd[CLIENT_PASS_LEN];
  314. const char *mode_ptr;
  315. /* Member or not? -- That's the question! */
  316. if (!Channel_IsMemberOf(Channel, Origin))
  317. return IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
  318. Client_ID(Origin), Channel_Name(Channel), Channel_Modes(Channel));
  319. /* The sender is a member: generate extended reply */
  320. strlcpy(the_modes, Channel_Modes(Channel), sizeof(the_modes));
  321. mode_ptr = the_modes;
  322. the_args[0] = '\0';
  323. while(*mode_ptr) {
  324. switch(*mode_ptr) {
  325. case 'l':
  326. snprintf(argadd, sizeof(argadd), " %lu", Channel_MaxUsers(Channel));
  327. strlcat(the_args, argadd, sizeof(the_args));
  328. break;
  329. case 'k':
  330. strlcat(the_args, " ", sizeof(the_args));
  331. strlcat(the_args, Channel_Key(Channel), sizeof(the_args));
  332. break;
  333. }
  334. mode_ptr++;
  335. }
  336. if (the_args[0])
  337. strlcat(the_modes, the_args, sizeof(the_modes));
  338. if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
  339. Client_ID(Origin), Channel_Name(Channel),
  340. the_modes))
  341. return DISCONNECTED;
  342. #ifndef STRICT_RFC
  343. if (!IRC_WriteStrClient(Origin, RPL_CREATIONTIME_MSG,
  344. Client_ID(Origin), Channel_Name(Channel),
  345. Channel_CreationTime(Channel)))
  346. return DISCONNECTED;
  347. #endif
  348. return CONNECTED;
  349. }
  350. /**
  351. * Handle channel mode and channel-user mode changes
  352. */
  353. static bool
  354. Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
  355. {
  356. char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2],
  357. argadd[CLIENT_PASS_LEN], *mode_ptr;
  358. bool connected, set, skiponce, retval, onchannel, modeok, use_servermode;
  359. int mode_arg, arg_arg, mode_arg_count = 0;
  360. CLIENT *client;
  361. long l;
  362. size_t len;
  363. if (Channel_IsModeless(Channel))
  364. return IRC_WriteStrClient(Client, ERR_NOCHANMODES_MSG,
  365. Client_ID(Client), Channel_Name(Channel));
  366. /* Mode request: let's answer it :-) */
  367. if (Req->argc <= 1)
  368. return Channel_Mode_Answer_Request(Origin, Channel);
  369. Channel_CheckAdminRights(Channel, Client, Origin,
  370. &onchannel, &modeok, &use_servermode);
  371. if (!onchannel && !modeok)
  372. return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG,
  373. Client_ID(Origin),
  374. Channel_Name(Channel));
  375. mode_arg = 1;
  376. mode_ptr = Req->argv[mode_arg];
  377. if (Req->argc > mode_arg + 1)
  378. arg_arg = mode_arg + 1;
  379. else
  380. arg_arg = -1;
  381. /* Initial state: set or unset modes? */
  382. skiponce = false;
  383. switch (*mode_ptr) {
  384. case '-':
  385. set = false;
  386. break;
  387. case '+':
  388. set = true;
  389. break;
  390. default:
  391. set = true;
  392. skiponce = true;
  393. }
  394. /* Prepare reply string */
  395. strcpy(the_modes, set ? "+" : "-");
  396. the_args[0] = '\0';
  397. x[1] = '\0';
  398. connected = CONNECTED;
  399. while (mode_ptr) {
  400. if (!skiponce)
  401. mode_ptr++;
  402. if (!*mode_ptr) {
  403. /* Try next argument if there's any */
  404. if (arg_arg < 0)
  405. break;
  406. if (arg_arg > mode_arg)
  407. mode_arg = arg_arg;
  408. else
  409. mode_arg++;
  410. if (mode_arg >= Req->argc)
  411. break;
  412. mode_ptr = Req->argv[mode_arg];
  413. if (Req->argc > mode_arg + 1)
  414. arg_arg = mode_arg + 1;
  415. else
  416. arg_arg = -1;
  417. }
  418. skiponce = false;
  419. switch (*mode_ptr) {
  420. case '+':
  421. case '-':
  422. if (((*mode_ptr == '+') && !set)
  423. || ((*mode_ptr == '-') && set)) {
  424. /* Action modifier ("+"/"-") must be changed ... */
  425. len = strlen(the_modes) - 1;
  426. if (the_modes[len] == '+' || the_modes[len] == '-') {
  427. /* Adjust last action modifier in result */
  428. the_modes[len] = *mode_ptr;
  429. } else {
  430. /* Append modifier character to result string */
  431. x[0] = *mode_ptr;
  432. strlcat(the_modes, x, sizeof(the_modes));
  433. }
  434. set = *mode_ptr == '+';
  435. }
  436. continue;
  437. }
  438. /* Are there arguments left? */
  439. if (arg_arg >= Req->argc)
  440. arg_arg = -1;
  441. /* Validate modes */
  442. x[0] = '\0';
  443. argadd[0] = '\0';
  444. client = NULL;
  445. switch (*mode_ptr) {
  446. /* --- Channel modes --- */
  447. case 'i': /* Invite only */
  448. case 'm': /* Moderated */
  449. case 'n': /* Only members can write */
  450. case 'R': /* Registered users only */
  451. case 's': /* Secret channel */
  452. case 't': /* Topic locked */
  453. case 'z': /* Secure connections only */
  454. if (modeok)
  455. x[0] = *mode_ptr;
  456. else
  457. connected = IRC_WriteStrClient(Origin,
  458. ERR_CHANOPRIVSNEEDED_MSG,
  459. Client_ID(Origin), Channel_Name(Channel));
  460. break;
  461. case 'k': /* Channel key */
  462. if (Mode_Limit_Reached(Client, mode_arg_count++))
  463. goto chan_exit;
  464. if (!set) {
  465. if (modeok)
  466. x[0] = *mode_ptr;
  467. else
  468. connected = IRC_WriteStrClient(Origin,
  469. ERR_CHANOPRIVSNEEDED_MSG,
  470. Client_ID(Origin),
  471. Channel_Name(Channel));
  472. break;
  473. }
  474. if (arg_arg > mode_arg) {
  475. if (modeok) {
  476. Channel_ModeDel(Channel, 'k');
  477. Channel_SetKey(Channel,
  478. Req->argv[arg_arg]);
  479. strlcpy(argadd, Channel_Key(Channel),
  480. sizeof(argadd));
  481. x[0] = *mode_ptr;
  482. } else {
  483. connected = IRC_WriteStrClient(Origin,
  484. ERR_CHANOPRIVSNEEDED_MSG,
  485. Client_ID(Origin),
  486. Channel_Name(Channel));
  487. }
  488. Req->argv[arg_arg][0] = '\0';
  489. arg_arg++;
  490. } else {
  491. connected = IRC_WriteStrClient(Origin,
  492. ERR_NEEDMOREPARAMS_MSG,
  493. Client_ID(Origin), Req->command);
  494. goto chan_exit;
  495. }
  496. break;
  497. case 'l': /* Member limit */
  498. if (Mode_Limit_Reached(Client, mode_arg_count++))
  499. goto chan_exit;
  500. if (!set) {
  501. if (modeok)
  502. x[0] = *mode_ptr;
  503. else
  504. connected = IRC_WriteStrClient(Origin,
  505. ERR_CHANOPRIVSNEEDED_MSG,
  506. Client_ID(Origin),
  507. Channel_Name(Channel));
  508. break;
  509. }
  510. if (arg_arg > mode_arg) {
  511. if (modeok) {
  512. l = atol(Req->argv[arg_arg]);
  513. if (l > 0 && l < 0xFFFF) {
  514. Channel_ModeDel(Channel, 'l');
  515. Channel_SetMaxUsers(Channel, l);
  516. snprintf(argadd, sizeof(argadd),
  517. "%ld", l);
  518. x[0] = *mode_ptr;
  519. }
  520. } else {
  521. connected = IRC_WriteStrClient(Origin,
  522. ERR_CHANOPRIVSNEEDED_MSG,
  523. Client_ID(Origin),
  524. Channel_Name(Channel));
  525. }
  526. Req->argv[arg_arg][0] = '\0';
  527. arg_arg++;
  528. } else {
  529. connected = IRC_WriteStrClient(Origin,
  530. ERR_NEEDMOREPARAMS_MSG,
  531. Client_ID(Origin), Req->command);
  532. goto chan_exit;
  533. }
  534. break;
  535. case 'O': /* IRC operators only */
  536. if (modeok) {
  537. /* Only IRC operators are allowed to
  538. * set the 'O' channel mode! */
  539. if (set && !(Client_OperByMe(Client)
  540. || Client_Type(Client) == CLIENT_SERVER))
  541. connected = IRC_WriteStrClient(Origin,
  542. ERR_NOPRIVILEGES_MSG,
  543. Client_ID(Origin));
  544. else
  545. x[0] = 'O';
  546. } else
  547. connected = IRC_WriteStrClient(Origin,
  548. ERR_CHANOPRIVSNEEDED_MSG,
  549. Client_ID(Origin),
  550. Channel_Name(Channel));
  551. break;
  552. case 'P': /* Persistent channel */
  553. if (modeok) {
  554. /* Only IRC operators are allowed to
  555. * set the 'P' channel mode! */
  556. if (set && !(Client_OperByMe(Client)
  557. || Client_Type(Client) == CLIENT_SERVER))
  558. connected = IRC_WriteStrClient(Origin,
  559. ERR_NOPRIVILEGES_MSG,
  560. Client_ID(Origin));
  561. else
  562. x[0] = 'P';
  563. } else
  564. connected = IRC_WriteStrClient(Origin,
  565. ERR_CHANOPRIVSNEEDED_MSG,
  566. Client_ID(Origin),
  567. Channel_Name(Channel));
  568. break;
  569. /* --- Channel user modes --- */
  570. case 'a':
  571. case 'h':
  572. case 'q':
  573. if (Client_Type(Client) != CLIENT_SERVER) {
  574. connected = IRC_WriteStrClient(Origin,
  575. ERR_CHANOPRIVSNEEDED_MSG,
  576. Client_ID(Origin),
  577. Channel_Name(Channel));
  578. goto chan_exit;
  579. }
  580. case 'o': /* Channel operator */
  581. case 'v': /* Voice */
  582. if (arg_arg > mode_arg) {
  583. if (modeok) {
  584. client = Client_Search(Req->argv[arg_arg]);
  585. if (client)
  586. x[0] = *mode_ptr;
  587. else
  588. connected = IRC_WriteStrClient(Client,
  589. ERR_NOSUCHNICK_MSG,
  590. Client_ID(Client),
  591. Req->argv[arg_arg]);
  592. } else {
  593. connected = IRC_WriteStrClient(Origin,
  594. ERR_CHANOPRIVSNEEDED_MSG,
  595. Client_ID(Origin),
  596. Channel_Name(Channel));
  597. }
  598. Req->argv[arg_arg][0] = '\0';
  599. arg_arg++;
  600. } else {
  601. connected = IRC_WriteStrClient(Origin,
  602. ERR_NEEDMOREPARAMS_MSG,
  603. Client_ID(Origin), Req->command);
  604. goto chan_exit;
  605. }
  606. break;
  607. /* --- Channel lists --- */
  608. case 'I': /* Invite lists */
  609. case 'b': /* Ban lists */
  610. case 'e': /* Channel exception lists */
  611. if (Mode_Limit_Reached(Client, mode_arg_count++))
  612. goto chan_exit;
  613. if (arg_arg > mode_arg) {
  614. /* modify list */
  615. if (modeok) {
  616. connected = set
  617. ? Add_To_List(*mode_ptr, Origin,
  618. Client, Channel,
  619. Req->argv[arg_arg])
  620. : Del_From_List(*mode_ptr, Origin,
  621. Client, Channel,
  622. Req->argv[arg_arg]);
  623. } else {
  624. connected = IRC_WriteStrClient(Origin,
  625. ERR_CHANOPRIVSNEEDED_MSG,
  626. Client_ID(Origin),
  627. Channel_Name(Channel));
  628. }
  629. Req->argv[arg_arg][0] = '\0';
  630. arg_arg++;
  631. } else {
  632. switch (*mode_ptr) {
  633. case 'I':
  634. Channel_ShowInvites(Origin, Channel);
  635. break;
  636. case 'b':
  637. Channel_ShowBans(Origin, Channel);
  638. break;
  639. case 'e':
  640. Channel_ShowExcepts(Origin, Channel);
  641. break;
  642. }
  643. }
  644. break;
  645. default:
  646. if (Client_Type(Client) != CLIENT_SERVER) {
  647. Log(LOG_DEBUG,
  648. "Unknown mode \"%c%c\" from \"%s\" on %s!?",
  649. set ? '+' : '-', *mode_ptr,
  650. Client_ID(Origin), Channel_Name(Channel));
  651. connected = IRC_WriteStrClient(Origin,
  652. ERR_UNKNOWNMODE_MSG,
  653. Client_ID(Origin), *mode_ptr,
  654. Channel_Name(Channel));
  655. x[0] = '\0';
  656. } else {
  657. Log(LOG_DEBUG,
  658. "Handling unknown mode \"%c%c\" from \"%s\" on %s ...",
  659. set ? '+' : '-', *mode_ptr,
  660. Client_ID(Origin), Channel_Name(Channel));
  661. x[0] = *mode_ptr;
  662. }
  663. }
  664. if (!connected)
  665. break;
  666. /* Is there a valid mode change? */
  667. if (!x[0])
  668. continue;
  669. /* Validate target client */
  670. if (client && (!Channel_IsMemberOf(Channel, client))) {
  671. if (!IRC_WriteStrClient
  672. (Origin, ERR_USERNOTINCHANNEL_MSG,
  673. Client_ID(Origin), Client_ID(client),
  674. Channel_Name(Channel)))
  675. break;
  676. continue;
  677. }
  678. if (client) {
  679. /* Channel-User-Mode */
  680. retval = set
  681. ? Channel_UserModeAdd(Channel, client, x[0])
  682. : Channel_UserModeDel(Channel, client, x[0]);
  683. if (retval) {
  684. strlcat(the_args, " ", sizeof(the_args));
  685. strlcat(the_args, Client_ID(client),
  686. sizeof(the_args));
  687. strlcat(the_modes, x, sizeof(the_modes));
  688. LogDebug
  689. ("User \"%s\": Mode change on %s, now \"%s\"",
  690. Client_Mask(client), Channel_Name(Channel),
  691. Channel_UserModes(Channel, client));
  692. }
  693. } else {
  694. /* Channel-Mode */
  695. retval = set
  696. ? Channel_ModeAdd(Channel, x[0])
  697. : Channel_ModeDel(Channel, x[0]);
  698. if (retval) {
  699. strlcat(the_modes, x, sizeof(the_modes));
  700. LogDebug("Channel %s: Mode change, now \"%s\".",
  701. Channel_Name(Channel),
  702. Channel_Modes(Channel));
  703. }
  704. }
  705. /* Are there additional arguments to add? */
  706. if (argadd[0]) {
  707. strlcat(the_args, " ", sizeof(the_args));
  708. strlcat(the_args, argadd, sizeof(the_args));
  709. }
  710. }
  711. chan_exit:
  712. /* Are there changed modes? */
  713. if (the_modes[1]) {
  714. /* Clean up mode string */
  715. len = strlen(the_modes) - 1;
  716. if ((the_modes[len] == '+') || (the_modes[len] == '-'))
  717. the_modes[len] = '\0';
  718. if (Client_Type(Client) == CLIENT_SERVER) {
  719. /* MODE requests for local channels from other servers
  720. * are definitely invalid! */
  721. if (Channel_IsLocal(Channel)) {
  722. Log(LOG_ALERT, "Got remote MODE command for local channel!? Ignored.");
  723. return CONNECTED;
  724. }
  725. /* Forward mode changes to channel users and all the
  726. * other remote servers: */
  727. IRC_WriteStrServersPrefix(Client, Origin,
  728. "MODE %s %s%s", Channel_Name(Channel),
  729. the_modes, the_args);
  730. IRC_WriteStrChannelPrefix(Client, Channel, Origin,
  731. false, "MODE %s %s%s", Channel_Name(Channel),
  732. the_modes, the_args);
  733. } else {
  734. if (use_servermode)
  735. Origin = Client_ThisServer();
  736. /* Send reply to client and inform other servers and channel users */
  737. connected = IRC_WriteStrClientPrefix(Client, Origin,
  738. "MODE %s %s%s", Channel_Name(Channel),
  739. the_modes, the_args);
  740. /* Only forward requests for non-local channels */
  741. if (!Channel_IsLocal(Channel))
  742. IRC_WriteStrServersPrefix(Client, Origin,
  743. "MODE %s %s%s", Channel_Name(Channel),
  744. the_modes, the_args);
  745. IRC_WriteStrChannelPrefix(Client, Channel, Origin,
  746. false, "MODE %s %s%s", Channel_Name(Channel),
  747. the_modes, the_args);
  748. }
  749. }
  750. IRC_SetPenalty(Client, 1);
  751. return connected;
  752. } /* Channel_Mode */
  753. GLOBAL bool
  754. IRC_AWAY( CLIENT *Client, REQUEST *Req )
  755. {
  756. assert( Client != NULL );
  757. assert( Req != NULL );
  758. if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  759. if(( Req->argc == 1 ) && (Req->argv[0][0] ))
  760. {
  761. Client_SetAway( Client, Req->argv[0] );
  762. Client_ModeAdd( Client, 'a' );
  763. IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
  764. return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
  765. }
  766. else
  767. {
  768. Client_ModeDel( Client, 'a' );
  769. IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
  770. return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
  771. }
  772. } /* IRC_AWAY */
  773. /**
  774. * Add entries to channel invite, ban and exception lists.
  775. *
  776. * @param what Can be 'I' for invite, 'b' for ban, and 'e' for exception list.
  777. * @param Prefix The originator of the command.
  778. * @param Client The sender of the command.
  779. * @param Channel The channel of which the list should be modified.
  780. * @param Pattern The pattern to add to the list.
  781. * @return CONNECTED or DISCONNECTED.
  782. */
  783. static bool
  784. Add_To_List(char what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel,
  785. const char *Pattern)
  786. {
  787. const char *mask;
  788. struct list_head *list;
  789. long int current_count;
  790. assert(Client != NULL);
  791. assert(Channel != NULL);
  792. assert(Pattern != NULL);
  793. assert(what == 'I' || what == 'b' || what == 'e');
  794. mask = Lists_MakeMask(Pattern);
  795. current_count = Lists_Count(Channel_GetListInvites(Channel))
  796. + Lists_Count(Channel_GetListExcepts(Channel))
  797. + Lists_Count(Channel_GetListBans(Channel));
  798. switch(what) {
  799. case 'I':
  800. list = Channel_GetListInvites(Channel);
  801. break;
  802. case 'b':
  803. list = Channel_GetListBans(Channel);
  804. break;
  805. case 'e':
  806. list = Channel_GetListExcepts(Channel);
  807. break;
  808. }
  809. if (Lists_CheckDupeMask(list, mask))
  810. return CONNECTED;
  811. if (Client_Type(Client) == CLIENT_USER &&
  812. current_count >= MAX_HNDL_CHANNEL_LISTS)
  813. return IRC_WriteStrClient(Client, ERR_LISTFULL_MSG,
  814. Client_ID(Client),
  815. Channel_Name(Channel), mask,
  816. MAX_HNDL_CHANNEL_LISTS);
  817. switch (what) {
  818. case 'I':
  819. if (!Channel_AddInvite(Channel, mask, false))
  820. return CONNECTED;
  821. break;
  822. case 'b':
  823. if (!Channel_AddBan(Channel, mask))
  824. return CONNECTED;
  825. break;
  826. case 'e':
  827. if (!Channel_AddExcept(Channel, mask))
  828. return CONNECTED;
  829. break;
  830. }
  831. return Send_ListChange(true, what, Prefix, Client, Channel, mask);
  832. }
  833. /**
  834. * Delete entries from channel invite, ban and exeption lists.
  835. *
  836. * @param what Can be 'I' for invite, 'b' for ban, and 'e' for exception list.
  837. * @param Prefix The originator of the command.
  838. * @param Client The sender of the command.
  839. * @param Channel The channel of which the list should be modified.
  840. * @param Pattern The pattern to add to the list.
  841. * @return CONNECTED or DISCONNECTED.
  842. */
  843. static bool
  844. Del_From_List(char what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel,
  845. const char *Pattern)
  846. {
  847. const char *mask;
  848. struct list_head *list;
  849. assert(Client != NULL);
  850. assert(Channel != NULL);
  851. assert(Pattern != NULL);
  852. assert(what == 'I' || what == 'b' || what == 'e');
  853. mask = Lists_MakeMask(Pattern);
  854. switch (what) {
  855. case 'I':
  856. list = Channel_GetListInvites(Channel);
  857. break;
  858. case 'b':
  859. list = Channel_GetListBans(Channel);
  860. break;
  861. case 'e':
  862. list = Channel_GetListExcepts(Channel);
  863. break;
  864. }
  865. if (!Lists_CheckDupeMask(list, mask))
  866. return CONNECTED;
  867. Lists_Del(list, mask);
  868. return Send_ListChange(false, what, Prefix, Client, Channel, mask);
  869. }
  870. /**
  871. * Send information about changed channel invite/ban/exception lists to clients.
  872. *
  873. * @param IsAdd true if the list item has been added, false otherwise.
  874. * @param ModeChar The mode to use (e. g. 'b' or 'I')
  875. * @param Prefix The originator of the mode list change.
  876. * @param Client The sender of the command.
  877. * @param Channel The channel of which the list has been modified.
  878. * @param Mask The mask which has been added or removed.
  879. * @return CONNECTED or DISCONNECTED.
  880. */
  881. static bool
  882. Send_ListChange(const bool IsAdd, const char ModeChar, CLIENT *Prefix,
  883. CLIENT *Client, CHANNEL *Channel, const char *Mask)
  884. {
  885. bool ok = true;
  886. /* Send confirmation to the client */
  887. if (Client_Type(Client) == CLIENT_USER)
  888. ok = IRC_WriteStrClientPrefix(Client, Prefix, "MODE %s %c%c %s",
  889. Channel_Name(Channel),
  890. IsAdd ? '+' : '-',
  891. ModeChar, Mask);
  892. /* to other servers */
  893. IRC_WriteStrServersPrefix(Client, Prefix, "MODE %s %c%c %s",
  894. Channel_Name(Channel), IsAdd ? '+' : '-',
  895. ModeChar, Mask);
  896. /* and local users in channel */
  897. IRC_WriteStrChannelPrefix(Client, Channel, Prefix, false,
  898. "MODE %s %c%c %s", Channel_Name(Channel),
  899. IsAdd ? '+' : '-', ModeChar, Mask );
  900. return ok;
  901. } /* Send_ListChange */
  902. /* -eof- */