irc-mode.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2010 Alexander Barton (alex@barton.de)
  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. * IRC commands for mode changes (MODE, AWAY, ...)
  12. */
  13. #include "portab.h"
  14. #include "imp.h"
  15. #include <assert.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include "defines.h"
  20. #include "conn.h"
  21. #include "channel.h"
  22. #include "irc-write.h"
  23. #include "lists.h"
  24. #include "log.h"
  25. #include "parse.h"
  26. #include "messages.h"
  27. #include "conf.h"
  28. #include "exp.h"
  29. #include "irc-mode.h"
  30. static bool Client_Mode PARAMS(( CLIENT *Client, REQUEST *Req, CLIENT *Origin,
  31. CLIENT *Target ));
  32. static bool Channel_Mode PARAMS(( CLIENT *Client, REQUEST *Req, CLIENT *Origin,
  33. CHANNEL *Channel ));
  34. static bool Add_Ban_Invite PARAMS((int what, CLIENT *Prefix, CLIENT *Client,
  35. CHANNEL *Channel, const char *Pattern));
  36. static bool Del_Ban_Invite PARAMS((int what, CLIENT *Prefix, CLIENT *Client,
  37. CHANNEL *Channel, const char *Pattern));
  38. static bool Send_ListChange PARAMS((const char *Mode, CLIENT *Prefix,
  39. CLIENT *Client, CHANNEL *Channel, const char *Mask));
  40. GLOBAL bool
  41. IRC_MODE( CLIENT *Client, REQUEST *Req )
  42. {
  43. CLIENT *cl, *origin;
  44. CHANNEL *chan;
  45. assert( Client != NULL );
  46. assert( Req != NULL );
  47. /* No parameters? */
  48. if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  49. /* Origin for answers */
  50. if( Client_Type( Client ) == CLIENT_SERVER )
  51. {
  52. origin = Client_Search( Req->prefix );
  53. if( ! origin ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  54. }
  55. else origin = Client;
  56. /* Channel or user mode? */
  57. cl = NULL; chan = NULL;
  58. if (Client_IsValidNick(Req->argv[0]))
  59. cl = Client_Search(Req->argv[0]);
  60. if (Channel_IsValidName(Req->argv[0]))
  61. chan = Channel_Search(Req->argv[0]);
  62. if (cl)
  63. return Client_Mode(Client, Req, origin, cl);
  64. if (chan)
  65. return Channel_Mode(Client, Req, origin, chan);
  66. /* No target found! */
  67. return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
  68. Client_ID(Client), Req->argv[0]);
  69. } /* IRC_MODE */
  70. static bool
  71. Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
  72. {
  73. /* Handle client mode requests */
  74. char the_modes[COMMAND_LEN], x[2], *mode_ptr;
  75. bool ok, set;
  76. int mode_arg;
  77. size_t len;
  78. /* Is the client allowed to request or change the modes? */
  79. if( Client_Type( Client ) == CLIENT_USER )
  80. {
  81. /* Users are only allowed to manipulate their own modes! */
  82. if( Target != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
  83. }
  84. /* Mode request: let's answer it :-) */
  85. if( Req->argc == 1 ) return IRC_WriteStrClient( Origin, RPL_UMODEIS_MSG, Client_ID( Origin ), Client_Modes( Target ));
  86. mode_arg = 1;
  87. mode_ptr = Req->argv[mode_arg];
  88. /* Initial state: set or unset modes? */
  89. if( *mode_ptr == '+' ) set = true;
  90. else if( *mode_ptr == '-' ) set = false;
  91. else return IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Origin ));
  92. /* Prepare reply string */
  93. if( set ) strcpy( the_modes, "+" );
  94. else strcpy( the_modes, "-" );
  95. x[1] = '\0';
  96. ok = CONNECTED;
  97. while( mode_ptr )
  98. {
  99. mode_ptr++;
  100. if( ! *mode_ptr )
  101. {
  102. /* Try next argument if there's any */
  103. mode_arg++;
  104. if( mode_arg < Req->argc ) mode_ptr = Req->argv[mode_arg];
  105. else break;
  106. }
  107. switch( *mode_ptr )
  108. {
  109. case '+':
  110. case '-':
  111. if((( *mode_ptr == '+' ) && ( ! set )) || (( *mode_ptr == '-' ) && ( set )))
  112. {
  113. /* Action modifier ("+"/"-") must be changed ... */
  114. len = strlen( the_modes ) - 1;
  115. if(( the_modes[len] == '+' ) || ( the_modes[len] == '-' ))
  116. {
  117. /* Adjust last action modifier in result */
  118. the_modes[len] = *mode_ptr;
  119. }
  120. else
  121. {
  122. /* Append modifier character to result string */
  123. x[0] = *mode_ptr;
  124. strlcat( the_modes, x, sizeof( the_modes ));
  125. }
  126. if( *mode_ptr == '+' ) set = true;
  127. else set = false;
  128. }
  129. continue;
  130. }
  131. /* Validate modes */
  132. x[0] = '\0';
  133. switch( *mode_ptr )
  134. {
  135. case 'i': /* Invisible */
  136. case 's': /* Server messages */
  137. case 'w': /* Wallops messages */
  138. x[0] = *mode_ptr;
  139. break;
  140. case 'a': /* Away */
  141. if( Client_Type( Client ) == CLIENT_SERVER )
  142. {
  143. x[0] = 'a';
  144. Client_SetAway( Origin, DEFAULT_AWAY_MSG );
  145. }
  146. else ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
  147. break;
  148. case 'c': /* Receive connect notices
  149. * (only settable by IRC operators!) */
  150. if(!set || Client_OperByMe(Origin)
  151. || Client_Type(Client) == CLIENT_SERVER)
  152. x[0] = 'c';
  153. else
  154. ok = IRC_WriteStrClient(Origin,
  155. ERR_NOPRIVILEGES_MSG,
  156. Client_ID(Origin));
  157. break;
  158. case 'o': /* IRC operator (only unsettable!) */
  159. if(( ! set ) || ( Client_Type( Client ) == CLIENT_SERVER ))
  160. {
  161. Client_SetOperByMe( Target, false );
  162. x[0] = 'o';
  163. }
  164. else ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
  165. break;
  166. case 'r': /* Restricted (only settable) */
  167. if(( set ) || ( Client_Type( Client ) == CLIENT_SERVER )) x[0] = 'r';
  168. else ok = IRC_WriteStrClient( Origin, ERR_RESTRICTED_MSG, Client_ID( Origin ));
  169. break;
  170. case 'x': /* Cloak hostname */
  171. if (Client_HasMode(Client, 'r'))
  172. IRC_WriteStrClient(Origin,
  173. ERR_RESTRICTED_MSG,
  174. Client_ID(Origin));
  175. else
  176. x[0] = 'x';
  177. break;
  178. default:
  179. Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Origin ));
  180. if( Client_Type( Client ) != CLIENT_SERVER ) ok = IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Origin ), set ? '+' : '-', *mode_ptr );
  181. x[0] = '\0';
  182. goto client_exit;
  183. }
  184. if( ! ok ) break;
  185. /* Is there a valid mode change? */
  186. if( ! x[0] ) continue;
  187. if( set )
  188. {
  189. /* Set mode */
  190. if( Client_ModeAdd( Target, x[0] )) strlcat( the_modes, x, sizeof( the_modes ));
  191. }
  192. else
  193. {
  194. /* Unset mode */
  195. if( Client_ModeDel( Target, x[0] )) strlcat( the_modes, x, sizeof( the_modes ));
  196. }
  197. }
  198. client_exit:
  199. /* Are there changed modes? */
  200. if( the_modes[1] )
  201. {
  202. /* Remoce needless action modifier characters */
  203. len = strlen( the_modes ) - 1;
  204. if(( the_modes[len] == '+' ) || ( the_modes[len] == '-' )) the_modes[len] = '\0';
  205. if( Client_Type( Client ) == CLIENT_SERVER )
  206. {
  207. /* Forward modes to other servers */
  208. IRC_WriteStrServersPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
  209. }
  210. else
  211. {
  212. /* Send reply to client and inform other servers */
  213. ok = IRC_WriteStrClientPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
  214. IRC_WriteStrServersPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
  215. }
  216. LogDebug("%s \"%s\": Mode change, now \"%s\".",
  217. Client_TypeText(Target), Client_Mask(Target),
  218. Client_Modes(Target));
  219. }
  220. IRC_SetPenalty( Client, 1 );
  221. return ok;
  222. } /* Client_Mode */
  223. static bool
  224. Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel)
  225. {
  226. char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], argadd[CLIENT_PASS_LEN];
  227. const char *mode_ptr;
  228. /* Member or not? -- That's the question! */
  229. if (!Channel_IsMemberOf(Channel, Origin))
  230. return IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
  231. Client_ID(Origin), Channel_Name(Channel), Channel_Modes(Channel));
  232. /* The sender is a member: generate extended reply */
  233. strlcpy(the_modes, Channel_Modes(Channel), sizeof(the_modes));
  234. mode_ptr = the_modes;
  235. the_args[0] = '\0';
  236. while(*mode_ptr) {
  237. switch(*mode_ptr) {
  238. case 'l':
  239. snprintf(argadd, sizeof(argadd), " %lu", Channel_MaxUsers(Channel));
  240. strlcat(the_args, argadd, sizeof(the_args));
  241. break;
  242. case 'k':
  243. strlcat(the_args, " ", sizeof(the_args));
  244. strlcat(the_args, Channel_Key(Channel), sizeof(the_args));
  245. break;
  246. }
  247. mode_ptr++;
  248. }
  249. if (the_args[0])
  250. strlcat(the_modes, the_args, sizeof(the_modes));
  251. if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
  252. Client_ID(Origin), Channel_Name(Channel),
  253. the_modes))
  254. return DISCONNECTED;
  255. #ifndef STRICT_RFC
  256. if (!IRC_WriteStrClient(Origin, RPL_CREATIONTIME_MSG,
  257. Client_ID(Origin), Channel_Name(Channel),
  258. Channel_CreationTime(Channel)))
  259. return DISCONNECTED;
  260. #endif
  261. return CONNECTED;
  262. }
  263. /**
  264. * Handle channel mode and channel-user mode changes
  265. */
  266. static bool
  267. Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
  268. {
  269. char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2],
  270. argadd[CLIENT_PASS_LEN], *mode_ptr;
  271. bool connected, set, skiponce, retval, onchannel;
  272. bool modeok = true, use_servermode = false;
  273. int mode_arg, arg_arg;
  274. CLIENT *client;
  275. long l;
  276. size_t len;
  277. if (Channel_IsModeless(Channel))
  278. return IRC_WriteStrClient(Client, ERR_NOCHANMODES_MSG,
  279. Client_ID(Client), Channel_Name(Channel));
  280. /* Mode request: let's answer it :-) */
  281. if (Req->argc <= 1)
  282. return Channel_Mode_Answer_Request(Origin, Channel);
  283. /* Is the user allowed to change modes? */
  284. if (Client_Type(Client) == CLIENT_USER) {
  285. /* Is the originating user on that channel? */
  286. onchannel = Channel_IsMemberOf(Channel, Origin);
  287. modeok = false;
  288. /* channel operator? */
  289. if (onchannel &&
  290. strchr(Channel_UserModes(Channel, Origin), 'o')) {
  291. modeok = true;
  292. } else if (Conf_OperCanMode) {
  293. /* IRC-Operators can use MODE as well */
  294. if (Client_OperByMe(Origin)) {
  295. modeok = true;
  296. if (Conf_OperServerMode)
  297. use_servermode = true; /* Change Origin to Server */
  298. }
  299. }
  300. if (!onchannel && !modeok)
  301. return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG,
  302. Client_ID(Origin), Channel_Name(Channel));
  303. }
  304. mode_arg = 1;
  305. mode_ptr = Req->argv[mode_arg];
  306. if (Req->argc > mode_arg + 1)
  307. arg_arg = mode_arg + 1;
  308. else
  309. arg_arg = -1;
  310. /* Initial state: set or unset modes? */
  311. skiponce = false;
  312. switch (*mode_ptr) {
  313. case '-':
  314. set = false;
  315. break;
  316. case '+':
  317. set = true;
  318. break;
  319. default:
  320. set = true;
  321. skiponce = true;
  322. }
  323. /* Prepare reply string */
  324. strcpy(the_modes, set ? "+" : "-");
  325. the_args[0] = '\0';
  326. x[1] = '\0';
  327. connected = CONNECTED;
  328. while (mode_ptr) {
  329. if (!skiponce)
  330. mode_ptr++;
  331. if (!*mode_ptr) {
  332. /* Try next argument if there's any */
  333. if (arg_arg > mode_arg)
  334. mode_arg = arg_arg;
  335. else
  336. mode_arg++;
  337. if (mode_arg >= Req->argc)
  338. break;
  339. mode_ptr = Req->argv[mode_arg];
  340. if (Req->argc > mode_arg + 1)
  341. arg_arg = mode_arg + 1;
  342. else
  343. arg_arg = -1;
  344. }
  345. skiponce = false;
  346. switch (*mode_ptr) {
  347. case '+':
  348. case '-':
  349. if (((*mode_ptr == '+') && !set)
  350. || ((*mode_ptr == '-') && set)) {
  351. /* Action modifier ("+"/"-") must be changed ... */
  352. len = strlen(the_modes) - 1;
  353. if (the_modes[len] == '+' || the_modes[len] == '-') {
  354. /* Adjust last action modifier in result */
  355. the_modes[len] = *mode_ptr;
  356. } else {
  357. /* Append modifier character to result string */
  358. x[0] = *mode_ptr;
  359. strlcat(the_modes, x, sizeof(the_modes));
  360. }
  361. set = *mode_ptr == '+';
  362. }
  363. continue;
  364. }
  365. /* Are there arguments left? */
  366. if (arg_arg >= Req->argc)
  367. arg_arg = -1;
  368. /* Validate modes */
  369. x[0] = '\0';
  370. argadd[0] = '\0';
  371. client = NULL;
  372. switch (*mode_ptr) {
  373. /* --- Channel modes --- */
  374. case 'i': /* Invite only */
  375. case 'm': /* Moderated */
  376. case 'n': /* Only members can write */
  377. case 's': /* Secret channel */
  378. case 't': /* Topic locked */
  379. case 'z': /* Secure connections only */
  380. if (modeok)
  381. x[0] = *mode_ptr;
  382. else
  383. connected = IRC_WriteStrClient(Origin,
  384. ERR_CHANOPRIVSNEEDED_MSG,
  385. Client_ID(Origin), Channel_Name(Channel));
  386. break;
  387. case 'k': /* Channel key */
  388. if (!set) {
  389. if (modeok)
  390. x[0] = *mode_ptr;
  391. else
  392. connected = IRC_WriteStrClient(Origin,
  393. ERR_CHANOPRIVSNEEDED_MSG,
  394. Client_ID(Origin),
  395. Channel_Name(Channel));
  396. break;
  397. }
  398. if (arg_arg > mode_arg) {
  399. if (modeok) {
  400. Channel_ModeDel(Channel, 'k');
  401. Channel_SetKey(Channel,
  402. Req->argv[arg_arg]);
  403. strlcpy(argadd, Channel_Key(Channel),
  404. sizeof(argadd));
  405. x[0] = *mode_ptr;
  406. } else {
  407. connected = IRC_WriteStrClient(Origin,
  408. ERR_CHANOPRIVSNEEDED_MSG,
  409. Client_ID(Origin),
  410. Channel_Name(Channel));
  411. }
  412. Req->argv[arg_arg][0] = '\0';
  413. arg_arg++;
  414. } else {
  415. connected = IRC_WriteStrClient(Origin,
  416. ERR_NEEDMOREPARAMS_MSG,
  417. Client_ID(Origin), Req->command);
  418. goto chan_exit;
  419. }
  420. break;
  421. case 'l': /* Member limit */
  422. if (!set) {
  423. if (modeok)
  424. x[0] = *mode_ptr;
  425. else
  426. connected = IRC_WriteStrClient(Origin,
  427. ERR_CHANOPRIVSNEEDED_MSG,
  428. Client_ID(Origin),
  429. Channel_Name(Channel));
  430. break;
  431. }
  432. if (arg_arg > mode_arg) {
  433. if (modeok) {
  434. l = atol(Req->argv[arg_arg]);
  435. if (l > 0 && l < 0xFFFF) {
  436. Channel_ModeDel(Channel, 'l');
  437. Channel_SetMaxUsers(Channel, l);
  438. snprintf(argadd, sizeof(argadd),
  439. "%ld", l);
  440. x[0] = *mode_ptr;
  441. }
  442. } else {
  443. connected = IRC_WriteStrClient(Origin,
  444. ERR_CHANOPRIVSNEEDED_MSG,
  445. Client_ID(Origin),
  446. Channel_Name(Channel));
  447. }
  448. Req->argv[arg_arg][0] = '\0';
  449. arg_arg++;
  450. } else {
  451. connected = IRC_WriteStrClient(Origin,
  452. ERR_NEEDMOREPARAMS_MSG,
  453. Client_ID(Origin), Req->command);
  454. goto chan_exit;
  455. }
  456. break;
  457. case 'P': /* Persistent channel */
  458. if (modeok) {
  459. /* Only IRC operators are allowed to
  460. * set the 'P' channel mode! */
  461. if (set && !(Client_OperByMe(Client)
  462. || Client_Type(Client) == CLIENT_SERVER))
  463. connected = IRC_WriteStrClient(Origin,
  464. ERR_NOPRIVILEGES_MSG,
  465. Client_ID(Origin));
  466. else
  467. x[0] = 'P';
  468. } else
  469. connected = IRC_WriteStrClient(Origin,
  470. ERR_CHANOPRIVSNEEDED_MSG,
  471. Client_ID(Origin),
  472. Channel_Name(Channel));
  473. break;
  474. /* --- Channel user modes --- */
  475. case 'o': /* Channel operator */
  476. case 'v': /* Voice */
  477. if (arg_arg > mode_arg) {
  478. if (modeok) {
  479. client = Client_Search(Req->argv[arg_arg]);
  480. if (client)
  481. x[0] = *mode_ptr;
  482. else
  483. connected = IRC_WriteStrClient(Client,
  484. ERR_NOSUCHNICK_MSG,
  485. Client_ID(Client),
  486. Req->argv[arg_arg]);
  487. } else {
  488. connected = IRC_WriteStrClient(Origin,
  489. ERR_CHANOPRIVSNEEDED_MSG,
  490. Client_ID(Origin),
  491. Channel_Name(Channel));
  492. }
  493. Req->argv[arg_arg][0] = '\0';
  494. arg_arg++;
  495. } else {
  496. connected = IRC_WriteStrClient(Origin,
  497. ERR_NEEDMOREPARAMS_MSG,
  498. Client_ID(Origin), Req->command);
  499. goto chan_exit;
  500. }
  501. break;
  502. /* --- Channel lists --- */
  503. case 'I': /* Invite lists */
  504. case 'b': /* Ban lists */
  505. if (arg_arg > mode_arg) {
  506. /* modify list */
  507. if (modeok) {
  508. connected = set
  509. ? Add_Ban_Invite(*mode_ptr, Origin,
  510. Client, Channel,
  511. Req->argv[arg_arg])
  512. : Del_Ban_Invite(*mode_ptr, Origin,
  513. Client, Channel,
  514. Req->argv[arg_arg]);
  515. } else {
  516. connected = IRC_WriteStrClient(Origin,
  517. ERR_CHANOPRIVSNEEDED_MSG,
  518. Client_ID(Origin),
  519. Channel_Name(Channel));
  520. }
  521. Req->argv[arg_arg][0] = '\0';
  522. arg_arg++;
  523. } else {
  524. if (*mode_ptr == 'I')
  525. Channel_ShowInvites(Origin, Channel);
  526. else
  527. Channel_ShowBans(Origin, Channel);
  528. }
  529. break;
  530. default:
  531. Log(LOG_DEBUG,
  532. "Unknown mode \"%c%c\" from \"%s\" on %s!?",
  533. set ? '+' : '-', *mode_ptr, Client_ID(Origin),
  534. Channel_Name(Channel));
  535. if (Client_Type(Client) != CLIENT_SERVER)
  536. connected = IRC_WriteStrClient(Origin,
  537. ERR_UMODEUNKNOWNFLAG2_MSG,
  538. Client_ID(Origin),
  539. set ? '+' : '-', *mode_ptr);
  540. x[0] = '\0';
  541. goto chan_exit;
  542. } /* switch() */
  543. if (!connected)
  544. break;
  545. /* Is there a valid mode change? */
  546. if (!x[0])
  547. continue;
  548. /* Validate target client */
  549. if (client && (!Channel_IsMemberOf(Channel, client))) {
  550. if (!IRC_WriteStrClient
  551. (Origin, ERR_USERNOTINCHANNEL_MSG,
  552. Client_ID(Origin), Client_ID(client),
  553. Channel_Name(Channel)))
  554. break;
  555. continue;
  556. }
  557. if (client) {
  558. /* Channel-User-Mode */
  559. retval = set
  560. ? Channel_UserModeAdd(Channel, client, x[0])
  561. : Channel_UserModeDel(Channel, client, x[0]);
  562. if (retval) {
  563. strlcat(the_args, " ", sizeof(the_args));
  564. strlcat(the_args, Client_ID(client),
  565. sizeof(the_args));
  566. strlcat(the_modes, x, sizeof(the_modes));
  567. LogDebug
  568. ("User \"%s\": Mode change on %s, now \"%s\"",
  569. Client_Mask(client), Channel_Name(Channel),
  570. Channel_UserModes(Channel, client));
  571. }
  572. } else {
  573. /* Channel-Mode */
  574. retval = set
  575. ? Channel_ModeAdd(Channel, x[0])
  576. : Channel_ModeDel(Channel, x[0]);
  577. if (retval) {
  578. strlcat(the_modes, x, sizeof(the_modes));
  579. LogDebug("Channel %s: Mode change, now \"%s\".",
  580. Channel_Name(Channel),
  581. Channel_Modes(Channel));
  582. }
  583. }
  584. /* Are there additional arguments to add? */
  585. if (argadd[0]) {
  586. strlcat(the_args, " ", sizeof(the_args));
  587. strlcat(the_args, argadd, sizeof(the_args));
  588. }
  589. }
  590. chan_exit:
  591. /* Are there changed modes? */
  592. if (the_modes[1]) {
  593. /* Clean up mode string */
  594. len = strlen(the_modes) - 1;
  595. if ((the_modes[len] == '+') || (the_modes[len] == '-'))
  596. the_modes[len] = '\0';
  597. if (Client_Type(Client) == CLIENT_SERVER) {
  598. /* MODE requests for local channels from other servers
  599. * are definitely invalid! */
  600. if (Channel_IsLocal(Channel)) {
  601. Log(LOG_ALERT, "Got remote MODE command for local channel!? Ignored.");
  602. return CONNECTED;
  603. }
  604. /* Forward mode changes to channel users and all the
  605. * other remote servers: */
  606. IRC_WriteStrServersPrefix(Client, Origin,
  607. "MODE %s %s%s", Channel_Name(Channel),
  608. the_modes, the_args);
  609. IRC_WriteStrChannelPrefix(Client, Channel, Origin,
  610. false, "MODE %s %s%s", Channel_Name(Channel),
  611. the_modes, the_args);
  612. } else {
  613. if (use_servermode)
  614. Origin = Client_ThisServer();
  615. /* Send reply to client and inform other servers and channel users */
  616. connected = IRC_WriteStrClientPrefix(Client, Origin,
  617. "MODE %s %s%s", Channel_Name(Channel),
  618. the_modes, the_args);
  619. /* Only forward requests for non-local channels */
  620. if (!Channel_IsLocal(Channel))
  621. IRC_WriteStrServersPrefix(Client, Origin,
  622. "MODE %s %s%s", Channel_Name(Channel),
  623. the_modes, the_args);
  624. IRC_WriteStrChannelPrefix(Client, Channel, Origin,
  625. false, "MODE %s %s%s", Channel_Name(Channel),
  626. the_modes, the_args);
  627. }
  628. }
  629. IRC_SetPenalty(Client, 1);
  630. return connected;
  631. } /* Channel_Mode */
  632. GLOBAL bool
  633. IRC_AWAY( CLIENT *Client, REQUEST *Req )
  634. {
  635. assert( Client != NULL );
  636. assert( Req != NULL );
  637. if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  638. if(( Req->argc == 1 ) && (Req->argv[0][0] ))
  639. {
  640. Client_SetAway( Client, Req->argv[0] );
  641. Client_ModeAdd( Client, 'a' );
  642. IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
  643. return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
  644. }
  645. else
  646. {
  647. Client_ModeDel( Client, 'a' );
  648. IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
  649. return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
  650. }
  651. } /* IRC_AWAY */
  652. static bool
  653. Add_Ban_Invite(int what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, const char *Pattern)
  654. {
  655. const char *mask;
  656. bool already;
  657. bool ret;
  658. assert( Client != NULL );
  659. assert( Channel != NULL );
  660. assert( Pattern != NULL );
  661. assert(what == 'I' || what == 'b');
  662. mask = Lists_MakeMask(Pattern);
  663. already = Lists_CheckDupeMask(Channel_GetListInvites(Channel), mask);
  664. if (!already) {
  665. if (what == 'I')
  666. ret = Channel_AddInvite(Channel, mask, false);
  667. else
  668. ret = Channel_AddBan(Channel, mask);
  669. if (!ret)
  670. return CONNECTED;
  671. }
  672. if (already && (Client_Type(Prefix) == CLIENT_SERVER))
  673. return CONNECTED;
  674. if (what == 'I')
  675. return Send_ListChange("+I", Prefix, Client, Channel, mask);
  676. return Send_ListChange("+b", Prefix, Client, Channel, mask);
  677. }
  678. static bool
  679. Del_Ban_Invite(int what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, const char *Pattern)
  680. {
  681. const char *mask;
  682. struct list_head *list;
  683. assert( Client != NULL );
  684. assert( Channel != NULL );
  685. assert( Pattern != NULL );
  686. assert(what == 'I' || what == 'b');
  687. mask = Lists_MakeMask( Pattern );
  688. if (what == 'I')
  689. list = Channel_GetListInvites(Channel);
  690. else
  691. list = Channel_GetListBans(Channel);
  692. Lists_Del(list, mask);
  693. if (what == 'I')
  694. return Send_ListChange( "-I", Prefix, Client, Channel, mask );
  695. return Send_ListChange( "-b", Prefix, Client, Channel, mask );
  696. }
  697. static bool
  698. Send_ListChange(const char *Mode, CLIENT *Prefix, CLIENT *Client,
  699. CHANNEL *Channel, const char *Mask)
  700. {
  701. bool ok;
  702. if( Client_Type( Client ) == CLIENT_USER )
  703. {
  704. /* send confirmation to client */
  705. ok = IRC_WriteStrClientPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
  706. }
  707. else ok = true;
  708. /* to other servers */
  709. IRC_WriteStrServersPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
  710. /* and local users in channel */
  711. IRC_WriteStrChannelPrefix( Client, Channel, Prefix, false, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
  712. return ok;
  713. } /* Send_ListChange */
  714. /* -eof- */