irc-channel.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * Please read the file COPYING, README and AUTHORS for more information.
  10. */
  11. #include "portab.h"
  12. /**
  13. * @file
  14. * IRC channel commands
  15. */
  16. #include "imp.h"
  17. #include <assert.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include "defines.h"
  22. #include "conn.h"
  23. #include "channel.h"
  24. #include "conn-func.h"
  25. #include "lists.h"
  26. #include "log.h"
  27. #include "match.h"
  28. #include "messages.h"
  29. #include "parse.h"
  30. #include "irc.h"
  31. #include "irc-info.h"
  32. #include "irc-macros.h"
  33. #include "irc-write.h"
  34. #include "conf.h"
  35. #include "exp.h"
  36. #include "irc-channel.h"
  37. /**
  38. * Part from all channels.
  39. *
  40. * RFC 2812, (3.2.1 Join message Command):
  41. * Note that this message accepts a special argument ("0"), which is a
  42. * special request to leave all channels the user is currently a member of.
  43. * The server will process this message as if the user had sent a PART
  44. * command (See Section 3.2.2) for each channel he is a member of.
  45. *
  46. * @param client Client that initiated the part request
  47. * @param target Client that should part all joined channels
  48. * @returns CONNECTED or DISCONNECTED
  49. */
  50. static bool
  51. part_from_all_channels(CLIENT* client, CLIENT *target)
  52. {
  53. CL2CHAN *cl2chan;
  54. CHANNEL *chan;
  55. while ((cl2chan = Channel_FirstChannelOf(target))) {
  56. chan = Channel_GetChannel(cl2chan);
  57. assert( chan != NULL );
  58. Channel_Part(target, client, Channel_Name(chan), Client_ID(target));
  59. }
  60. return CONNECTED;
  61. } /* part_from_all_channels */
  62. /**
  63. * Check weather a local client is allowed to join an already existing
  64. * channel or not.
  65. *
  66. * @param Client Client that sent the JOIN command
  67. * @param chan Channel to check
  68. * @param channame Name of the channel
  69. * @param key Provided channel key (or NULL)
  70. * @returns true if client is allowed to join, false otherwise
  71. */
  72. static bool
  73. join_allowed(CLIENT *Client, CHANNEL *chan, const char *channame,
  74. const char *key)
  75. {
  76. bool is_invited, is_banned, is_exception;
  77. /* Allow IRC operators to overwrite channel limits */
  78. if (Client_HasMode(Client, 'o'))
  79. return true;
  80. is_banned = Lists_Check(Channel_GetListBans(chan), Client);
  81. is_exception = Lists_Check(Channel_GetListExcepts(chan), Client);
  82. is_invited = Lists_Check(Channel_GetListInvites(chan), Client);
  83. if (is_banned && !is_invited && !is_exception) {
  84. /* Client is banned from channel (and not on invite list) */
  85. IRC_WriteErrClient(Client, ERR_BANNEDFROMCHAN_MSG,
  86. Client_ID(Client), channame);
  87. return false;
  88. }
  89. if (Channel_HasMode(chan, 'i') && !is_invited) {
  90. /* Channel is "invite-only" and client is not on invite list */
  91. IRC_WriteErrClient(Client, ERR_INVITEONLYCHAN_MSG,
  92. Client_ID(Client), channame);
  93. return false;
  94. }
  95. if (!Channel_CheckKey(chan, Client, key ? key : "")) {
  96. /* Channel is protected by a channel key and the client
  97. * didn't specify the correct one */
  98. IRC_WriteErrClient(Client, ERR_BADCHANNELKEY_MSG,
  99. Client_ID(Client), channame);
  100. return false;
  101. }
  102. if (Channel_HasMode(chan, 'l') &&
  103. (Channel_MaxUsers(chan) <= Channel_MemberCount(chan))) {
  104. /* There are more clints joined to this channel than allowed */
  105. IRC_WriteErrClient(Client, ERR_CHANNELISFULL_MSG,
  106. Client_ID(Client), channame);
  107. return false;
  108. }
  109. if (Channel_HasMode(chan, 'z') && !Conn_UsesSSL(Client_Conn(Client))) {
  110. /* Only "secure" clients are allowed, but clients doesn't
  111. * use SSL encryption */
  112. IRC_WriteErrClient(Client, ERR_SECURECHANNEL_MSG,
  113. Client_ID(Client), channame);
  114. return false;
  115. }
  116. if (Channel_HasMode(chan, 'O') && !Client_HasMode(Client, 'o')) {
  117. /* Only IRC operators are allowed! */
  118. IRC_WriteErrClient(Client, ERR_OPONLYCHANNEL_MSG,
  119. Client_ID(Client), channame);
  120. return false;
  121. }
  122. if (Channel_HasMode(chan, 'R') && !Client_HasMode(Client, 'R')) {
  123. /* Only registered users are allowed! */
  124. IRC_WriteErrClient(Client, ERR_REGONLYCHANNEL_MSG,
  125. Client_ID(Client), channame);
  126. return false;
  127. }
  128. return true;
  129. } /* join_allowed */
  130. /**
  131. * Set user channel modes.
  132. *
  133. * @param chan Channel
  134. * @param target User to set modes for
  135. * @param flags Channel modes to add
  136. */
  137. static void
  138. join_set_channelmodes(CHANNEL *chan, CLIENT *target, const char *flags)
  139. {
  140. if (flags) {
  141. while (*flags) {
  142. Channel_UserModeAdd(chan, target, *flags);
  143. flags++;
  144. }
  145. }
  146. /* If the channel is persistent (+P) and client is an IRC op:
  147. * make client chanop, if not disabled in configuration. */
  148. if (Channel_HasMode(chan, 'P') && Conf_OperChanPAutoOp
  149. && Client_HasMode(target, 'o'))
  150. Channel_UserModeAdd(chan, target, 'o');
  151. } /* join_set_channelmodes */
  152. /**
  153. * Forward JOIN command to a specific server
  154. *
  155. * This function differentiates between servers using RFC 2813 mode that
  156. * support the JOIN command with appended ASCII 7 character and channel
  157. * modes, and servers using RFC 1459 protocol which require separate JOIN
  158. * and MODE commands.
  159. *
  160. * @param To Forward JOIN (and MODE) command to this peer server
  161. * @param Prefix Client used to prefix the genrated commands
  162. * @param Data Parameters of JOIN command to forward, probably
  163. * containing channel modes separated by ASCII 7.
  164. */
  165. static void
  166. cb_join_forward(CLIENT *To, CLIENT *Prefix, void *Data)
  167. {
  168. CONN_ID conn;
  169. char str[COMMAND_LEN], *ptr = NULL;
  170. strlcpy(str, (char *)Data, sizeof(str));
  171. conn = Client_Conn(To);
  172. if (Conn_Options(conn) & CONN_RFC1459) {
  173. /* RFC 1459 compatibility mode, appended modes are NOT
  174. * supported, so strip them off! */
  175. ptr = strchr(str, 0x7);
  176. if (ptr)
  177. *ptr++ = '\0';
  178. }
  179. IRC_WriteStrClientPrefix(To, Prefix, "JOIN %s", str);
  180. if (ptr && *ptr)
  181. IRC_WriteStrClientPrefix(To, Prefix, "MODE %s +%s %s", str, ptr,
  182. Client_ID(Prefix));
  183. } /* cb_join_forward */
  184. /**
  185. * Forward JOIN command to all servers
  186. *
  187. * This function calls cb_join_forward(), which differentiates between
  188. * protocol implementations (e.g. RFC 2812, RFC 1459).
  189. *
  190. * @param Client Client used to prefix the genrated commands
  191. * @param target Forward JOIN (and MODE) command to this peer server
  192. * @param chan Channel structure
  193. * @param channame Channel name
  194. */
  195. static void
  196. join_forward(CLIENT *Client, CLIENT *target, CHANNEL *chan,
  197. const char *channame)
  198. {
  199. char modes[CHANNEL_MODE_LEN], str[COMMAND_LEN];
  200. /* RFC 2813, 4.2.1: channel modes are separated from the channel
  201. * name with ASCII 7, if any, and not spaces: */
  202. strlcpy(&modes[1], Channel_UserModes(chan, target), sizeof(modes) - 1);
  203. if (modes[1])
  204. modes[0] = 0x7;
  205. else
  206. modes[0] = '\0';
  207. /* forward to other servers (if it is not a local channel) */
  208. if (!Channel_IsLocal(chan)) {
  209. snprintf(str, sizeof(str), "%s%s", channame, modes);
  210. IRC_WriteStrServersPrefixFlag_CB(Client, target, '\0',
  211. cb_join_forward, str);
  212. }
  213. /* tell users in this channel about the new client */
  214. IRC_WriteStrChannelPrefix(Client, chan, target, false,
  215. "JOIN :%s", channame);
  216. /* synchronize channel modes */
  217. if (modes[1]) {
  218. IRC_WriteStrChannelPrefix(Client, chan, target, false,
  219. "MODE %s +%s %s", channame,
  220. &modes[1], Client_ID(target));
  221. }
  222. } /* join_forward */
  223. /**
  224. * Acknowledge user JOIN request and send "channel info" numerics.
  225. *
  226. * @param Client Client used to prefix the genrated commands
  227. * @param target Forward commands/numerics to this user
  228. * @param chan Channel structure
  229. * @param channame Channel name
  230. */
  231. static bool
  232. join_send_topic(CLIENT *Client, CLIENT *target, CHANNEL *chan,
  233. const char *channame)
  234. {
  235. const char *topic;
  236. if (Client_Type(Client) != CLIENT_USER)
  237. return true;
  238. /* acknowledge join */
  239. if (!IRC_WriteStrClientPrefix(Client, target, "JOIN :%s", channame))
  240. return false;
  241. /* Send topic to client, if any */
  242. topic = Channel_Topic(chan);
  243. assert(topic != NULL);
  244. if (*topic) {
  245. if (!IRC_WriteStrClient(Client, RPL_TOPIC_MSG,
  246. Client_ID(Client), channame, topic))
  247. return false;
  248. #ifndef STRICT_RFC
  249. if (!IRC_WriteStrClient(Client, RPL_TOPICSETBY_MSG,
  250. Client_ID(Client), channame,
  251. Channel_TopicWho(chan),
  252. Channel_TopicTime(chan)))
  253. return false;
  254. #endif
  255. }
  256. /* send list of channel members to client */
  257. if (!IRC_Send_NAMES(Client, chan))
  258. return false;
  259. return IRC_WriteStrClient(Client, RPL_ENDOFNAMES_MSG, Client_ID(Client),
  260. Channel_Name(chan));
  261. } /* join_send_topic */
  262. /**
  263. * Handler for the IRC "JOIN" command.
  264. *
  265. * @param Client The client from which this command has been received.
  266. * @param Req Request structure with prefix and all parameters.
  267. * @return CONNECTED or DISCONNECTED.
  268. */
  269. GLOBAL bool
  270. IRC_JOIN( CLIENT *Client, REQUEST *Req )
  271. {
  272. char *channame, *key = NULL, *flags, *lastkey = NULL, *lastchan = NULL;
  273. CLIENT *target;
  274. CHANNEL *chan;
  275. assert (Client != NULL);
  276. assert (Req != NULL);
  277. _IRC_GET_SENDER_OR_RETURN_(target, Req, Client)
  278. /* Is argument "0"? */
  279. if (Req->argc == 1 && !strncmp("0", Req->argv[0], 2))
  280. return part_from_all_channels(Client, target);
  281. /* Are channel keys given? */
  282. if (Req->argc > 1)
  283. key = strtok_r(Req->argv[1], ",", &lastkey);
  284. channame = Req->argv[0];
  285. channame = strtok_r(channame, ",", &lastchan);
  286. /* Make sure that "channame" is not the empty string ("JOIN :") */
  287. if (!channame) {
  288. IRC_SetPenalty(Client, 2);
  289. return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
  290. Client_ID(Client), Req->command);
  291. }
  292. while (channame) {
  293. flags = NULL;
  294. /* Did the server include channel-user-modes? */
  295. if (Client_Type(Client) == CLIENT_SERVER) {
  296. flags = strchr(channame, 0x7);
  297. if (flags) {
  298. *flags = '\0';
  299. flags++;
  300. }
  301. }
  302. chan = Channel_Search(channame);
  303. /* Local client? */
  304. if (Client_Type(Client) == CLIENT_USER) {
  305. if (chan) {
  306. /* Already existing channel: already member? */
  307. if (Channel_IsMemberOf(chan, Client))
  308. goto join_next;
  309. } else {
  310. /* Channel must be created */
  311. if (!strchr(Conf_AllowedChannelTypes, channame[0])) {
  312. /* ... but channel type is not allowed! */
  313. IRC_WriteErrClient(Client,
  314. ERR_NOSUCHCHANNEL_MSG,
  315. Client_ID(Client), channame);
  316. goto join_next;
  317. }
  318. }
  319. /* Test if the user has reached the channel limit */
  320. if ((Conf_MaxJoins > 0) &&
  321. (Channel_CountForUser(Client) >= Conf_MaxJoins)) {
  322. if (!IRC_WriteErrClient(Client,
  323. ERR_TOOMANYCHANNELS_MSG,
  324. Client_ID(Client), channame))
  325. return DISCONNECTED;
  326. goto join_next;
  327. }
  328. if (chan) {
  329. /* Already existing channel: check if the
  330. * client is allowed to join */
  331. if (!join_allowed(Client, chan, channame, key))
  332. goto join_next;
  333. } else {
  334. /* New channel: first user will become channel
  335. * operator unless this is a modeless channel */
  336. if (*channame != '+')
  337. flags = "o";
  338. }
  339. /* Local client: update idle time */
  340. Conn_UpdateIdle(Client_Conn(Client));
  341. } else {
  342. /* Remote server: we don't need to know whether the
  343. * client is invited or not, but we have to make sure
  344. * that the "one shot" entries (generated by INVITE
  345. * commands) in this list become deleted when a user
  346. * joins a channel this way. */
  347. if (chan)
  348. (void)Lists_Check(Channel_GetListInvites(chan),
  349. target);
  350. }
  351. /* Join channel (and create channel if it doesn't exist) */
  352. if (!Channel_Join(target, channame))
  353. goto join_next;
  354. if (!chan) { /* channel is new; it has been created above */
  355. chan = Channel_Search(channame);
  356. assert(chan != NULL);
  357. if (Channel_IsModeless(chan)) {
  358. Channel_ModeAdd(chan, 't'); /* /TOPIC not allowed */
  359. Channel_ModeAdd(chan, 'n'); /* no external msgs */
  360. }
  361. }
  362. assert(chan != NULL);
  363. join_set_channelmodes(chan, target, flags);
  364. join_forward(Client, target, chan, channame);
  365. if (!join_send_topic(Client, target, chan, channame))
  366. break; /* write error */
  367. join_next:
  368. /* next channel? */
  369. channame = strtok_r(NULL, ",", &lastchan);
  370. if (channame && key)
  371. key = strtok_r(NULL, ",", &lastkey);
  372. }
  373. return CONNECTED;
  374. } /* IRC_JOIN */
  375. /**
  376. * Handler for the IRC "PART" command.
  377. *
  378. * @param Client The client from which this command has been received.
  379. * @param Req Request structure with prefix and all parameters.
  380. * @return CONNECTED or DISCONNECTED.
  381. */
  382. GLOBAL bool
  383. IRC_PART(CLIENT * Client, REQUEST * Req)
  384. {
  385. CLIENT *target;
  386. char *chan;
  387. assert(Client != NULL);
  388. assert(Req != NULL);
  389. _IRC_GET_SENDER_OR_RETURN_(target, Req, Client)
  390. /* Loop over all the given channel names */
  391. chan = strtok(Req->argv[0], ",");
  392. /* Make sure that "chan" is not the empty string ("PART :") */
  393. if (!chan) {
  394. IRC_SetPenalty(Client, 2);
  395. return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
  396. Client_ID(Client), Req->command);
  397. }
  398. while (chan) {
  399. Channel_Part(target, Client, chan,
  400. Req->argc > 1 ? Req->argv[1] : Client_ID(target));
  401. chan = strtok(NULL, ",");
  402. }
  403. /* Update idle time, if local client */
  404. if (Client_Conn(Client) > NONE)
  405. Conn_UpdateIdle(Client_Conn(Client));
  406. return CONNECTED;
  407. } /* IRC_PART */
  408. /**
  409. * Handler for the IRC "TOPIC" command.
  410. *
  411. * @param Client The client from which this command has been received.
  412. * @param Req Request structure with prefix and all parameters.
  413. * @return CONNECTED or DISCONNECTED.
  414. */
  415. GLOBAL bool
  416. IRC_TOPIC( CLIENT *Client, REQUEST *Req )
  417. {
  418. CHANNEL *chan;
  419. CLIENT *from;
  420. char *topic;
  421. bool r, topic_power;
  422. assert( Client != NULL );
  423. assert( Req != NULL );
  424. IRC_SetPenalty(Client, 1);
  425. _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
  426. chan = Channel_Search(Req->argv[0]);
  427. if (!chan)
  428. return IRC_WriteErrClient(from, ERR_NOSUCHCHANNEL_MSG,
  429. Client_ID(from), Req->argv[0]);
  430. /* Only remote servers and channel members are allowed to change the
  431. * channel topic, and IRC operators when the Conf_OperCanMode option
  432. * is set in the server configuration. */
  433. if (Client_Type(Client) != CLIENT_SERVER) {
  434. topic_power = Client_HasMode(from, 'o');
  435. if (!Channel_IsMemberOf(chan, from)
  436. && !(Conf_OperCanMode && topic_power))
  437. return IRC_WriteErrClient(from, ERR_NOTONCHANNEL_MSG,
  438. Client_ID(from), Req->argv[0]);
  439. } else
  440. topic_power = true;
  441. if (Req->argc == 1) {
  442. /* Request actual topic */
  443. topic = Channel_Topic(chan);
  444. if (*topic) {
  445. r = IRC_WriteStrClient(from, RPL_TOPIC_MSG,
  446. Client_ID(Client),
  447. Channel_Name(chan), topic);
  448. #ifndef STRICT_RFC
  449. if (!r)
  450. return r;
  451. r = IRC_WriteStrClient(from, RPL_TOPICSETBY_MSG,
  452. Client_ID(Client),
  453. Channel_Name(chan),
  454. Channel_TopicWho(chan),
  455. Channel_TopicTime(chan));
  456. #endif
  457. return r;
  458. }
  459. else
  460. return IRC_WriteStrClient(from, RPL_NOTOPIC_MSG,
  461. Client_ID(from),
  462. Channel_Name(chan));
  463. }
  464. if (Channel_HasMode(chan, 't')) {
  465. /* Topic Lock. Is the user a channel op or IRC operator? */
  466. if(!topic_power &&
  467. !Channel_UserHasMode(chan, from, 'h') &&
  468. !Channel_UserHasMode(chan, from, 'o') &&
  469. !Channel_UserHasMode(chan, from, 'a') &&
  470. !Channel_UserHasMode(chan, from, 'q'))
  471. return IRC_WriteErrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
  472. Client_ID(from),
  473. Channel_Name(chan));
  474. }
  475. /* Set new topic */
  476. Channel_SetTopic(chan, from, Req->argv[1]);
  477. LogDebug("%s \"%s\" set topic on \"%s\": %s",
  478. Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
  479. Req->argv[1][0] ? Req->argv[1] : "<none>");
  480. if (Conf_OperServerMode)
  481. from = Client_ThisServer();
  482. /* Update channel and forward new topic to other servers */
  483. if (!Channel_IsLocal(chan))
  484. IRC_WriteStrServersPrefix(Client, from, "TOPIC %s :%s",
  485. Req->argv[0], Req->argv[1]);
  486. IRC_WriteStrChannelPrefix(Client, chan, from, false, "TOPIC %s :%s",
  487. Req->argv[0], Req->argv[1]);
  488. if (Client_Type(Client) == CLIENT_USER)
  489. return IRC_WriteStrClientPrefix(Client, Client, "TOPIC %s :%s",
  490. Req->argv[0], Req->argv[1]);
  491. else
  492. return CONNECTED;
  493. } /* IRC_TOPIC */
  494. /**
  495. * Handler for the IRC "LIST" command.
  496. *
  497. * @param Client The client from which this command has been received.
  498. * @param Req Request structure with prefix and all parameters.
  499. * @return CONNECTED or DISCONNECTED.
  500. */
  501. GLOBAL bool
  502. IRC_LIST( CLIENT *Client, REQUEST *Req )
  503. {
  504. char *pattern;
  505. CHANNEL *chan;
  506. CLIENT *from, *target;
  507. int count = 0;
  508. assert(Client != NULL);
  509. assert(Req != NULL);
  510. IRC_SetPenalty(Client, 2);
  511. _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
  512. if (Req->argc > 0)
  513. pattern = strtok(Req->argv[0], ",");
  514. else
  515. pattern = "*";
  516. if (Req->argc == 2) {
  517. /* Forward to other server? */
  518. target = Client_Search(Req->argv[1]);
  519. if (! target || Client_Type(target) != CLIENT_SERVER)
  520. return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
  521. Client_ID(Client),
  522. Req->argv[1]);
  523. if (target != Client_ThisServer()) {
  524. /* Target is indeed an other server, forward it! */
  525. return IRC_WriteStrClientPrefix(target, from,
  526. "LIST %s :%s",
  527. Req->argv[0],
  528. Req->argv[1]);
  529. }
  530. }
  531. while (pattern) {
  532. /* Loop through all the channels */
  533. if (Req->argc > 0)
  534. ngt_LowerStr(pattern);
  535. chan = Channel_First();
  536. while (chan) {
  537. /* Check search pattern */
  538. if (MatchCaseInsensitive(pattern, Channel_Name(chan))) {
  539. /* Gotcha! */
  540. if (!Channel_HasMode(chan, 's')
  541. || Channel_IsMemberOf(chan, from)
  542. || (!Conf_MorePrivacy
  543. && Client_HasMode(Client, 'o')
  544. && Client_Conn(Client) > NONE))
  545. {
  546. if ((Conf_MaxListSize > 0)
  547. && IRC_CheckListTooBig(from, count,
  548. Conf_MaxListSize,
  549. "LIST"))
  550. break;
  551. if (!IRC_WriteStrClient(from,
  552. RPL_LIST_MSG, Client_ID(from),
  553. Channel_Name(chan),
  554. Channel_MemberCount(chan),
  555. Channel_Topic( chan )))
  556. return DISCONNECTED;
  557. count++;
  558. }
  559. }
  560. chan = Channel_Next(chan);
  561. }
  562. /* Get next name ... */
  563. if(Req->argc > 0)
  564. pattern = strtok(NULL, ",");
  565. else
  566. pattern = NULL;
  567. }
  568. return IRC_WriteStrClient(from, RPL_LISTEND_MSG, Client_ID(from));
  569. } /* IRC_LIST */
  570. /**
  571. * Handler for the IRC+ "CHANINFO" command.
  572. *
  573. * @param Client The client from which this command has been received.
  574. * @param Req Request structure with prefix and all parameters.
  575. * @return CONNECTED or DISCONNECTED.
  576. */
  577. GLOBAL bool
  578. IRC_CHANINFO( CLIENT *Client, REQUEST *Req )
  579. {
  580. char modes_add[COMMAND_LEN], l[16];
  581. CLIENT *from;
  582. CHANNEL *chan;
  583. int arg_topic;
  584. assert( Client != NULL );
  585. assert( Req != NULL );
  586. /* Bad number of parameters? */
  587. if (Req->argc < 2 || Req->argc == 4 || Req->argc > 5) {
  588. IRC_SetPenalty(Client, 2);
  589. return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
  590. Client_ID(Client), Req->command);
  591. }
  592. /* Compatibility kludge */
  593. if (Req->argc == 5)
  594. arg_topic = 4;
  595. else if(Req->argc == 3)
  596. arg_topic = 2;
  597. else
  598. arg_topic = -1;
  599. _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
  600. /* Search or create channel */
  601. chan = Channel_Search( Req->argv[0] );
  602. if (!chan)
  603. chan = Channel_Create( Req->argv[0] );
  604. if (!chan)
  605. return CONNECTED;
  606. if (Req->argv[1][0] == '+') {
  607. if (!*Channel_Modes(chan)) {
  608. /* OK, this channel doesn't have modes yet,
  609. * set the received ones: */
  610. Channel_SetModes(chan, &Req->argv[1][1]);
  611. if(Req->argc == 5) {
  612. if(Channel_HasMode(chan, 'k'))
  613. Channel_SetKey(chan, Req->argv[2]);
  614. if(Channel_HasMode(chan, 'l'))
  615. Channel_SetMaxUsers(chan, atol(Req->argv[3]));
  616. } else {
  617. /* Delete modes which we never want to inherit */
  618. Channel_ModeDel(chan, 'l');
  619. Channel_ModeDel(chan, 'k');
  620. }
  621. strcpy(modes_add, "");
  622. if (Channel_HasMode(chan, 'l')) {
  623. snprintf(l, sizeof(l), " %lu",
  624. Channel_MaxUsers(chan));
  625. strlcat(modes_add, l, sizeof(modes_add));
  626. }
  627. if (Channel_HasMode(chan, 'k')) {
  628. strlcat(modes_add, " ", sizeof(modes_add));
  629. strlcat(modes_add, Channel_Key(chan),
  630. sizeof(modes_add));
  631. }
  632. /* Inform members of this channel */
  633. IRC_WriteStrChannelPrefix(Client, chan, from, false,
  634. "MODE %s +%s%s", Req->argv[0],
  635. Channel_Modes(chan), modes_add);
  636. }
  637. }
  638. else
  639. Log(LOG_WARNING, "CHANINFO: invalid MODE format ignored!");
  640. if (arg_topic > 0) {
  641. /* We got a topic */
  642. if (!*Channel_Topic(chan) && Req->argv[arg_topic][0]) {
  643. /* OK, there is no topic jet */
  644. Channel_SetTopic(chan, Client, Req->argv[arg_topic]);
  645. IRC_WriteStrChannelPrefix(Client, chan, from, false,
  646. "TOPIC %s :%s", Req->argv[0], Channel_Topic(chan));
  647. }
  648. }
  649. /* Forward CHANINFO to other servers */
  650. if (Req->argc == 5)
  651. IRC_WriteStrServersPrefixFlag(Client, from, 'C',
  652. "CHANINFO %s %s %s %s :%s",
  653. Req->argv[0], Req->argv[1],
  654. Req->argv[2], Req->argv[3],
  655. Req->argv[4]);
  656. else if (Req->argc == 3)
  657. IRC_WriteStrServersPrefixFlag(Client, from, 'C',
  658. "CHANINFO %s %s :%s",
  659. Req->argv[0], Req->argv[1],
  660. Req->argv[2]);
  661. else
  662. IRC_WriteStrServersPrefixFlag(Client, from, 'C',
  663. "CHANINFO %s %s",
  664. Req->argv[0], Req->argv[1]);
  665. return CONNECTED;
  666. } /* IRC_CHANINFO */
  667. /* -eof- */