irc-mode.c 20 KB

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