irc-mode.c 30 KB

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