irc-channel.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  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 channel commands
  12. */
  13. #include "portab.h"
  14. #include "imp.h"
  15. #include <assert.h>
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include "defines.h"
  20. #include "conn.h"
  21. #include "channel.h"
  22. #include "conn-func.h"
  23. #include "lists.h"
  24. #include "log.h"
  25. #include "match.h"
  26. #include "messages.h"
  27. #include "parse.h"
  28. #include "irc-info.h"
  29. #include "irc-write.h"
  30. #include "conf.h"
  31. #include "exp.h"
  32. #include "irc-channel.h"
  33. /*
  34. * RFC 2812, (3.2.1 Join message Command):
  35. * Note that this message
  36. * accepts a special argument ("0"), which is a special request to leave all
  37. * channels the user is currently a member of. The server will process this
  38. * message as if the user had sent a PART command (See Section 3.2.2) for
  39. * each channel he is a member of.
  40. */
  41. static bool
  42. part_from_all_channels(CLIENT* client, CLIENT *target)
  43. {
  44. CL2CHAN *cl2chan;
  45. CHANNEL *chan;
  46. while ((cl2chan = Channel_FirstChannelOf(target))) {
  47. chan = Channel_GetChannel(cl2chan);
  48. assert( chan != NULL );
  49. Channel_Part(target, client, Channel_Name(chan), Client_ID(target));
  50. }
  51. return CONNECTED;
  52. }
  53. /**
  54. * Check weather a local client is allowed to join an already existing
  55. * channel or not.
  56. * @param Client Client that sent the JOIN command
  57. * @param chan Channel to check
  58. * @param channame Name of the channel
  59. * @param key Provided channel key (or NULL if none has been provided)
  60. * @return true if client is allowed to join channel, false otherwise
  61. */
  62. static bool
  63. join_allowed(CLIENT *Client, CHANNEL *chan, const char *channame,
  64. const char *key)
  65. {
  66. bool is_invited, is_banned;
  67. const char *channel_modes;
  68. /* Allow IRC operators to overwrite channel limits */
  69. if (strchr(Client_Modes(Client), 'o'))
  70. return true;
  71. is_banned = Lists_Check(Channel_GetListBans(chan), Client);
  72. is_invited = Lists_Check(Channel_GetListInvites(chan), Client);
  73. if (is_banned && !is_invited) {
  74. /* Client is banned from channel (and not on invite list) */
  75. IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG,
  76. Client_ID(Client), channame);
  77. return false;
  78. }
  79. channel_modes = Channel_Modes(chan);
  80. if (strchr(channel_modes, 'i') && !is_invited) {
  81. /* Channel is "invite-only" and client is not on invite list */
  82. IRC_WriteStrClient(Client, ERR_INVITEONLYCHAN_MSG,
  83. Client_ID(Client), channame);
  84. return false;
  85. }
  86. if (!Channel_CheckKey(chan, Client, key ? key : "")) {
  87. /* Channel is protected by a channel key and the client
  88. * didn't specify the correct one */
  89. IRC_WriteStrClient(Client, ERR_BADCHANNELKEY_MSG,
  90. Client_ID(Client), channame);
  91. return false;
  92. }
  93. if (strchr(channel_modes, 'l') &&
  94. (Channel_MaxUsers(chan) <= Channel_MemberCount(chan))) {
  95. /* There are more clints joined to this channel than allowed */
  96. IRC_WriteStrClient(Client, ERR_CHANNELISFULL_MSG,
  97. Client_ID(Client), channame);
  98. return false;
  99. }
  100. if (strchr(channel_modes, 'z') && !Conn_UsesSSL(Client_Conn(Client))) {
  101. /* Only "secure" clients are allowed, but clients doesn't
  102. * use SSL encryption */
  103. IRC_WriteStrClient(Client, ERR_SECURECHANNEL_MSG,
  104. Client_ID(Client), channame);
  105. return false;
  106. }
  107. return true;
  108. }
  109. static void
  110. join_set_channelmodes(CHANNEL *chan, CLIENT *target, const char *flags)
  111. {
  112. if (flags) {
  113. while (*flags) {
  114. Channel_UserModeAdd(chan, target, *flags);
  115. flags++;
  116. }
  117. }
  118. /* If channel persistent and client is ircop: make client chanop */
  119. if (strchr(Channel_Modes(chan), 'P') && strchr(Client_Modes(target), 'o'))
  120. Channel_UserModeAdd(chan, target, 'o');
  121. }
  122. static void
  123. cb_join_forward(CLIENT *To, CLIENT *Prefix, void *Data)
  124. {
  125. CONN_ID conn;
  126. char str[COMMAND_LEN], *ptr = NULL;
  127. strlcpy(str, (char *)Data, sizeof(str));
  128. conn = Client_Conn(To);
  129. if (Conn_Options(conn) & CONN_RFC1459) {
  130. /* RFC 1459 compatibility mode, appended modes are NOT
  131. * supported, so strip them off! */
  132. ptr = strchr(str, 0x7);
  133. if (ptr)
  134. *ptr++ = '\0';
  135. }
  136. IRC_WriteStrClientPrefix(To, Prefix, "JOIN %s", str);
  137. if (ptr && *ptr)
  138. IRC_WriteStrClientPrefix(To, Prefix, "MODE %s +%s %s", str, ptr,
  139. Client_ID(Prefix));
  140. } /* cb_join_forward */
  141. static void
  142. join_forward(CLIENT *Client, CLIENT *target, CHANNEL *chan,
  143. const char *channame)
  144. {
  145. char modes[CHANNEL_MODE_LEN], str[COMMAND_LEN];
  146. strlcpy(&modes[1], Channel_UserModes(chan, target), sizeof(modes) - 1);
  147. if (modes[1])
  148. modes[0] = 0x7;
  149. else
  150. modes[0] = '\0';
  151. /* forward to other servers (if it is not a local channel) */
  152. if (!Channel_IsLocal(chan)) {
  153. snprintf(str, sizeof(str), "%s%s", channame, modes);
  154. IRC_WriteStrServersPrefixFlag_CB(Client, target, '\0',
  155. cb_join_forward, str);
  156. }
  157. /* tell users in this channel about the new client */
  158. IRC_WriteStrChannelPrefix(Client, chan, target, false,
  159. "JOIN :%s", channame);
  160. /* syncronize channel modes */
  161. if (modes[1]) {
  162. IRC_WriteStrChannelPrefix(Client, chan, target, false,
  163. "MODE %s +%s %s", channame,
  164. &modes[1], Client_ID(target));
  165. }
  166. } /* join_forward */
  167. static bool
  168. join_send_topic(CLIENT *Client, CLIENT *target, CHANNEL *chan,
  169. const char *channame)
  170. {
  171. const char *topic;
  172. if (Client_Type(Client) != CLIENT_USER)
  173. return true;
  174. /* acknowledge join */
  175. if (!IRC_WriteStrClientPrefix(Client, target, "JOIN :%s", channame))
  176. return false;
  177. /* Send topic to client, if any */
  178. topic = Channel_Topic(chan);
  179. assert(topic != NULL);
  180. if (*topic) {
  181. if (!IRC_WriteStrClient(Client, RPL_TOPIC_MSG,
  182. Client_ID(Client), channame, topic))
  183. return false;
  184. #ifndef STRICT_RFC
  185. if (!IRC_WriteStrClient(Client, RPL_TOPICSETBY_MSG,
  186. Client_ID(Client), channame,
  187. Channel_TopicWho(chan),
  188. Channel_TopicTime(chan)))
  189. return false;
  190. #endif
  191. }
  192. /* send list of channel members to client */
  193. if (!IRC_Send_NAMES(Client, chan))
  194. return false;
  195. return IRC_WriteStrClient(Client, RPL_ENDOFNAMES_MSG, Client_ID(Client), Channel_Name(chan));
  196. }
  197. GLOBAL bool
  198. IRC_JOIN( CLIENT *Client, REQUEST *Req )
  199. {
  200. char *channame, *key = NULL, *flags, *lastkey = NULL, *lastchan = NULL;
  201. CLIENT *target;
  202. CHANNEL *chan;
  203. assert( Client != NULL );
  204. assert( Req != NULL );
  205. /* Bad number of arguments? */
  206. if (Req->argc < 1 || Req->argc > 2)
  207. return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
  208. Client_ID(Client), Req->command);
  209. /* Who is the sender? */
  210. if (Client_Type(Client) == CLIENT_SERVER)
  211. target = Client_Search(Req->prefix);
  212. else
  213. target = Client;
  214. if (!target)
  215. return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID(Client), Req->prefix);
  216. /* Is argument "0"? */
  217. if (Req->argc == 1 && !strncmp("0", Req->argv[0], 2))
  218. return part_from_all_channels(Client, target);
  219. /* Are channel keys given? */
  220. if (Req->argc > 1)
  221. key = strtok_r(Req->argv[1], ",", &lastkey);
  222. channame = Req->argv[0];
  223. channame = strtok_r(channame, ",", &lastchan);
  224. /* Make sure that "channame" is not the empty string ("JOIN :") */
  225. if (! channame)
  226. return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
  227. Client_ID(Client), Req->command);
  228. while (channame) {
  229. flags = NULL;
  230. /* Did the server include channel-user-modes? */
  231. if (Client_Type(Client) == CLIENT_SERVER) {
  232. flags = strchr(channame, 0x7);
  233. if (flags) {
  234. *flags = '\0';
  235. flags++;
  236. }
  237. }
  238. chan = Channel_Search(channame);
  239. if (!chan && Conf_PredefChannelsOnly) {
  240. /* channel must be created, but server does not allow this */
  241. IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG, Client_ID(Client), channame);
  242. break;
  243. }
  244. /* Local client? */
  245. if (Client_Type(Client) == CLIENT_USER) {
  246. /* Test if the user has reached the channel limit */
  247. if ((Conf_MaxJoins > 0) &&
  248. (Channel_CountForUser(Client) >= Conf_MaxJoins))
  249. return IRC_WriteStrClient(Client,
  250. ERR_TOOMANYCHANNELS_MSG,
  251. Client_ID(Client), channame);
  252. if (chan) {
  253. /* Already existing channel: check if the
  254. * client is allowed to join */
  255. if (!join_allowed(Client, chan, channame, key))
  256. break;
  257. } else {
  258. /* New channel: first user will become channel
  259. * operator unless this is a modeless channel */
  260. if (*channame != '+')
  261. flags = "o";
  262. }
  263. /* Local client: update idle time */
  264. Conn_UpdateIdle(Client_Conn(Client));
  265. } else {
  266. /* Remote server: we don't need to know whether the
  267. * client is invited or not, but we have to make sure
  268. * that the "one shot" entries (generated by INVITE
  269. * commands) in this list become deleted when a user
  270. * joins a channel this way. */
  271. if (chan)
  272. (void)Lists_Check(Channel_GetListInvites(chan),
  273. target);
  274. }
  275. /* Join channel (and create channel if it doesn't exist) */
  276. if (!Channel_Join(target, channame))
  277. break;
  278. if (!chan) { /* channel is new; it has been created above */
  279. chan = Channel_Search(channame);
  280. assert(chan != NULL);
  281. if (Channel_IsModeless(chan)) {
  282. Channel_ModeAdd(chan, 't'); /* /TOPIC not allowed */
  283. Channel_ModeAdd(chan, 'n'); /* no external msgs */
  284. }
  285. }
  286. assert(chan != NULL);
  287. join_set_channelmodes(chan, target, flags);
  288. join_forward(Client, target, chan, channame);
  289. if (!join_send_topic(Client, target, chan, channame))
  290. break; /* write error */
  291. /* next channel? */
  292. channame = strtok_r(NULL, ",", &lastchan);
  293. if (channame && key)
  294. key = strtok_r(NULL, ",", &lastkey);
  295. }
  296. return CONNECTED;
  297. } /* IRC_JOIN */
  298. /**
  299. * Handler for the IRC "PART" command.
  300. */
  301. GLOBAL bool
  302. IRC_PART(CLIENT * Client, REQUEST * Req)
  303. {
  304. CLIENT *target;
  305. char *chan;
  306. assert(Client != NULL);
  307. assert(Req != NULL);
  308. if (Req->argc < 1 || Req->argc > 2)
  309. return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
  310. Client_ID(Client), Req->command);
  311. /* Get the sender */
  312. if (Client_Type(Client) == CLIENT_SERVER)
  313. target = Client_Search(Req->prefix);
  314. else
  315. target = Client;
  316. if (!target)
  317. return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
  318. Client_ID(Client), Req->prefix);
  319. /* Loop over all the given channel names */
  320. chan = strtok(Req->argv[0], ",");
  321. /* Make sure that "chan" is not the empty string ("PART :") */
  322. if (! chan)
  323. return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
  324. Client_ID(Client), Req->command);
  325. while (chan) {
  326. Channel_Part(target, Client, chan,
  327. Req->argc > 1 ? Req->argv[1] : Client_ID(target));
  328. chan = strtok(NULL, ",");
  329. }
  330. /* Update idle time, if local client */
  331. if (Client_Conn(Client) > NONE)
  332. Conn_UpdateIdle(Client_Conn(Client));
  333. return CONNECTED;
  334. } /* IRC_PART */
  335. GLOBAL bool
  336. IRC_TOPIC( CLIENT *Client, REQUEST *Req )
  337. {
  338. CHANNEL *chan;
  339. CLIENT *from;
  340. char *topic;
  341. bool r;
  342. assert( Client != NULL );
  343. assert( Req != NULL );
  344. if ((Req->argc < 1) || (Req->argc > 2))
  345. return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
  346. if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
  347. else from = Client;
  348. if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  349. /* Welcher Channel? */
  350. chan = Channel_Search( Req->argv[0] );
  351. if( ! chan ) return IRC_WriteStrClient( from, ERR_NOSUCHCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
  352. /* Ist der User Mitglied in dem Channel? */
  353. if( ! Channel_IsMemberOf( chan, from )) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
  354. if( Req->argc == 1 )
  355. {
  356. /* Request actual topic */
  357. topic = Channel_Topic(chan);
  358. if (*topic) {
  359. r = IRC_WriteStrClient(from, RPL_TOPIC_MSG,
  360. Client_ID(Client), Channel_Name(chan), topic);
  361. #ifndef STRICT_RFC
  362. r = IRC_WriteStrClient(from, RPL_TOPICSETBY_MSG,
  363. Client_ID(Client), Channel_Name(chan),
  364. Channel_TopicWho(chan),
  365. Channel_TopicTime(chan));
  366. #endif
  367. return r;
  368. }
  369. else
  370. return IRC_WriteStrClient(from, RPL_NOTOPIC_MSG,
  371. Client_ID(from), Channel_Name(chan));
  372. }
  373. if( strchr( Channel_Modes( chan ), 't' ))
  374. {
  375. /* Topic Lock. Ist der User ein Channel Operator? */
  376. if( ! strchr( Channel_UserModes( chan, from ), 'o' )) return IRC_WriteStrClient( from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( from ), Channel_Name( chan ));
  377. }
  378. /* Set new topic */
  379. Channel_SetTopic(chan, from, Req->argv[1]);
  380. LogDebug("%s \"%s\" set topic on \"%s\": %s",
  381. Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
  382. Req->argv[1][0] ? Req->argv[1] : "<none>");
  383. /* Update channel and forward new topic to other servers */
  384. if (!Channel_IsLocal(chan))
  385. IRC_WriteStrServersPrefix(Client, from, "TOPIC %s :%s",
  386. Req->argv[0], Req->argv[1]);
  387. IRC_WriteStrChannelPrefix(Client, chan, from, false, "TOPIC %s :%s",
  388. Req->argv[0], Req->argv[1]);
  389. if (Client_Type(Client) == CLIENT_USER)
  390. return IRC_WriteStrClientPrefix(Client, Client, "TOPIC %s :%s",
  391. Req->argv[0], Req->argv[1]);
  392. else
  393. return CONNECTED;
  394. } /* IRC_TOPIC */
  395. /**
  396. * Handler for the IRC "LIST" command.
  397. * This implementation handles the local case as well as the forwarding of the
  398. * LIST command to other servers in the IRC network.
  399. */
  400. GLOBAL bool
  401. IRC_LIST( CLIENT *Client, REQUEST *Req )
  402. {
  403. char *pattern;
  404. CHANNEL *chan;
  405. CLIENT *from, *target;
  406. assert( Client != NULL );
  407. assert( Req != NULL );
  408. /* Bad number of prameters? */
  409. if( Req->argc > 2 )
  410. return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG,
  411. Client_ID( Client ), Req->command );
  412. if( Req->argc > 0 )
  413. pattern = strtok( Req->argv[0], "," );
  414. else
  415. pattern = "*";
  416. /* Get sender from prefix, if any */
  417. if( Client_Type( Client ) == CLIENT_SERVER )
  418. from = Client_Search( Req->prefix );
  419. else
  420. from = Client;
  421. if( ! from )
  422. return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG,
  423. Client_ID( Client ), Req->prefix );
  424. if( Req->argc == 2 )
  425. {
  426. /* Forward to other server? */
  427. target = Client_Search( Req->argv[1] );
  428. if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
  429. return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG,
  430. Client_ID( Client ), Req->argv[1] );
  431. if( target != Client_ThisServer( ))
  432. {
  433. /* Target is indeed an other server, forward it! */
  434. return IRC_WriteStrClientPrefix( target, from,
  435. "LIST %s :%s", Client_ID( from ),
  436. Req->argv[1] );
  437. }
  438. }
  439. while( pattern )
  440. {
  441. /* Loop through all the channels */
  442. chan = Channel_First( );
  443. while( chan )
  444. {
  445. /* Check search pattern */
  446. if( Match( pattern, Channel_Name( chan )))
  447. {
  448. /* Gotcha! */
  449. if( ! strchr( Channel_Modes( chan ), 's' ) ||
  450. Channel_IsMemberOf( chan, from ))
  451. {
  452. if( ! IRC_WriteStrClient( from,
  453. RPL_LIST_MSG, Client_ID( from ),
  454. Channel_Name( chan ),
  455. Channel_MemberCount( chan ),
  456. Channel_Topic( chan )))
  457. return DISCONNECTED;
  458. }
  459. }
  460. chan = Channel_Next( chan );
  461. }
  462. /* Get next name ... */
  463. if( Req->argc > 0 )
  464. pattern = strtok( NULL, "," );
  465. else
  466. pattern = NULL;
  467. }
  468. return IRC_WriteStrClient( from, RPL_LISTEND_MSG, Client_ID( from ));
  469. } /* IRC_LIST */
  470. GLOBAL bool
  471. IRC_CHANINFO( CLIENT *Client, REQUEST *Req )
  472. {
  473. char modes_add[COMMAND_LEN], l[16], *ptr;
  474. CLIENT *from;
  475. CHANNEL *chan;
  476. int arg_topic;
  477. assert( Client != NULL );
  478. assert( Req != NULL );
  479. /* Bad number of parameters? */
  480. if(( Req->argc < 2 ) || ( Req->argc == 4 ) || ( Req->argc > 5 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  481. /* Compatibility kludge */
  482. if( Req->argc == 5 ) arg_topic = 4;
  483. else if( Req->argc == 3 ) arg_topic = 2;
  484. else arg_topic = -1;
  485. /* Search origin */
  486. from = Client_Search( Req->prefix );
  487. if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  488. /* Search or create channel */
  489. chan = Channel_Search( Req->argv[0] );
  490. if( ! chan ) chan = Channel_Create( Req->argv[0] );
  491. if( ! chan ) return CONNECTED;
  492. if( Req->argv[1][0] == '+' )
  493. {
  494. ptr = Channel_Modes( chan );
  495. if( ! *ptr )
  496. {
  497. /* OK, this channel doesn't have modes jet, set the received ones: */
  498. Channel_SetModes( chan, &Req->argv[1][1] );
  499. if( Req->argc == 5 )
  500. {
  501. if( strchr( Channel_Modes( chan ), 'k' )) Channel_SetKey( chan, Req->argv[2] );
  502. if( strchr( Channel_Modes( chan ), 'l' )) Channel_SetMaxUsers( chan, atol( Req->argv[3] ));
  503. }
  504. else
  505. {
  506. /* Delete modes which we never want to inherit */
  507. Channel_ModeDel( chan, 'l' );
  508. Channel_ModeDel( chan, 'k' );
  509. }
  510. strcpy( modes_add, "" );
  511. ptr = Channel_Modes( chan );
  512. while( *ptr )
  513. {
  514. if( *ptr == 'l' )
  515. {
  516. snprintf( l, sizeof( l ), " %lu", Channel_MaxUsers( chan ));
  517. strlcat( modes_add, l, sizeof( modes_add ));
  518. }
  519. if( *ptr == 'k' )
  520. {
  521. strlcat( modes_add, " ", sizeof( modes_add ));
  522. strlcat( modes_add, Channel_Key( chan ), sizeof( modes_add ));
  523. }
  524. ptr++;
  525. }
  526. /* Inform members of this channel */
  527. IRC_WriteStrChannelPrefix( Client, chan, from, false, "MODE %s +%s%s", Req->argv[0], Channel_Modes( chan ), modes_add );
  528. }
  529. }
  530. else Log( LOG_WARNING, "CHANINFO: invalid MODE format ignored!" );
  531. if( arg_topic > 0 )
  532. {
  533. /* We got a topic */
  534. ptr = Channel_Topic( chan );
  535. if(( ! *ptr ) && ( Req->argv[arg_topic][0] ))
  536. {
  537. /* OK, there is no topic jet */
  538. Channel_SetTopic(chan, Client, Req->argv[arg_topic]);
  539. IRC_WriteStrChannelPrefix(Client, chan, from, false,
  540. "TOPIC %s :%s", Req->argv[0], Channel_Topic(chan));
  541. }
  542. }
  543. /* Forward CHANINFO to other serevrs */
  544. if( Req->argc == 5 ) IRC_WriteStrServersPrefixFlag( Client, from, 'C', "CHANINFO %s %s %s %s :%s", Req->argv[0], Req->argv[1], Req->argv[2], Req->argv[3], Req->argv[4] );
  545. else if( Req->argc == 3 ) IRC_WriteStrServersPrefixFlag( Client, from, 'C', "CHANINFO %s %s :%s", Req->argv[0], Req->argv[1], Req->argv[2] );
  546. else IRC_WriteStrServersPrefixFlag( Client, from, 'C', "CHANINFO %s %s", Req->argv[0], Req->argv[1] );
  547. return CONNECTED;
  548. } /* IRC_CHANINFO */
  549. /* -eof- */