irc-mode.c 21 KB

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