irc-channel.c 16 KB

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