irc-mode.c 30 KB

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