irc-channel.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  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.35 2006/03/16 20:14:16 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. GLOBAL bool
  36. IRC_JOIN( CLIENT *Client, REQUEST *Req )
  37. {
  38. char *channame, *channame_ptr, *key, *key_ptr, *flags, *topic, modes[8];
  39. bool is_new_chan, is_invited, is_banned;
  40. CLIENT *target;
  41. CHANNEL *chan;
  42. assert( Client != NULL );
  43. assert( Req != NULL );
  44. /* Bad number of arguments? */
  45. if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  46. /* Who is the sender? */
  47. if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
  48. else target = Client;
  49. if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  50. /* Are channel keys given? */
  51. if (Req->argc > 1) {
  52. key = Req->argv[1];
  53. key_ptr = strchr(key, ',');
  54. if (key_ptr) *key_ptr = '\0';
  55. }
  56. else
  57. key = key_ptr = NULL;
  58. channame = Req->argv[0];
  59. channame_ptr = strchr(channame, ',');
  60. if (channame_ptr) *channame_ptr = '\0';
  61. /* Channel-Namen durchgehen */
  62. while (channame)
  63. {
  64. chan = NULL; flags = NULL;
  65. /* wird der Channel neu angelegt? */
  66. if( Channel_Search( channame )) is_new_chan = false;
  67. else is_new_chan = true;
  68. /* Hat ein Server Channel-User-Modes uebergeben? */
  69. if( Client_Type( Client ) == CLIENT_SERVER )
  70. {
  71. /* Channel-Flags extrahieren */
  72. flags = strchr( channame, 0x7 );
  73. if( flags )
  74. {
  75. *flags = '\0';
  76. flags++;
  77. }
  78. }
  79. /* Local client? */
  80. if( Client_Type( Client ) == CLIENT_USER )
  81. {
  82. /* Test if the user has reached his maximum channel count */
  83. if(( Conf_MaxJoins > 0 ) && ( Channel_CountForUser( Client ) >= Conf_MaxJoins ))
  84. return IRC_WriteStrClient( Client, ERR_TOOMANYCHANNELS_MSG,
  85. Client_ID( Client ), channame );
  86. /* Existiert der Channel bereits, oder wird er im Moment neu erzeugt? */
  87. if( is_new_chan )
  88. {
  89. /* Erster User im Channel: Operator-Flag setzen */
  90. flags = "o";
  91. }
  92. else
  93. {
  94. /* Existierenden Channel suchen */
  95. chan = Channel_Search( channame );
  96. assert( chan != NULL );
  97. is_banned = Lists_CheckBanned( target, chan );
  98. is_invited = Lists_CheckInvited( target, chan );
  99. /* Testen, ob Client gebanned ist */
  100. if(( is_banned == true) && ( is_invited == false ))
  101. {
  102. /* Client ist gebanned (und nicht invited): */
  103. IRC_WriteStrClient( Client, ERR_BANNEDFROMCHAN_MSG, Client_ID( Client ), channame );
  104. /* Try next name, if any */
  105. channame = strtok( NULL, "," );
  106. continue;
  107. }
  108. /* Ist der Channel "invite-only"? */
  109. if(( strchr( Channel_Modes( chan ), 'i' )) && ( is_invited == false ))
  110. {
  111. /* Channel ist "invite-only" und Client wurde nicht invited: */
  112. IRC_WriteStrClient( Client, ERR_INVITEONLYCHAN_MSG, Client_ID( Client ), channame );
  113. /* Try next name, if any */
  114. channame = strtok( NULL, "," );
  115. continue;
  116. }
  117. /* Is the channel protected by a key? */
  118. if(( strchr( Channel_Modes( chan ), 'k' )) && ( strcmp( Channel_Key( chan ), key ? key : "" ) != 0 ))
  119. {
  120. /* Bad channel key! */
  121. IRC_WriteStrClient( Client, ERR_BADCHANNELKEY_MSG, Client_ID( Client ), channame );
  122. /* Try next name, if any */
  123. channame = strtok( NULL, "," );
  124. continue;
  125. }
  126. /* Are there already too many members? */
  127. if(( strchr( Channel_Modes( chan ), 'l' )) && ( Channel_MaxUsers( chan ) <= Channel_MemberCount( chan )))
  128. {
  129. /* Bad channel key! */
  130. IRC_WriteStrClient( Client, ERR_CHANNELISFULL_MSG, Client_ID( Client ), channame );
  131. /* Try next name, if any */
  132. channame = strtok( NULL, "," );
  133. continue;
  134. }
  135. }
  136. }
  137. else
  138. {
  139. /* Remote server: we don't need to know whether the
  140. * client is invited or not, but we have to make sure
  141. * that the "one shot" entries (generated by INVITE
  142. * commands) in this list become deleted when a user
  143. * joins a channel this way. */
  144. chan = Channel_Search( channame );
  145. if( chan != NULL ) (void)Lists_CheckInvited( target, chan );
  146. }
  147. /* Channel joinen (und ggf. anlegen) */
  148. if( ! Channel_Join( target, channame ))
  149. {
  150. /* naechsten Namen ermitteln */
  151. channame = strtok( NULL, "," );
  152. continue;
  153. }
  154. if( ! chan ) chan = Channel_Search( channame );
  155. assert( chan != NULL );
  156. /* Modes setzen (wenn vorhanden) */
  157. while( flags && *flags )
  158. {
  159. Channel_UserModeAdd( chan, target, *flags );
  160. flags++;
  161. }
  162. /* Wenn persistenter Channel und IRC-Operator: zum Channel-OP machen */
  163. if(( strchr( Channel_Modes( chan ), 'P' )) && ( strchr( Client_Modes( target ), 'o' ))) Channel_UserModeAdd( chan, target, 'o' );
  164. /* Muessen Modes an andere Server gemeldet werden? */
  165. strlcpy( &modes[1], Channel_UserModes( chan, target ), sizeof( modes ) - 1 );
  166. if( modes[1] ) modes[0] = 0x7;
  167. else modes[0] = '\0';
  168. /* An andere Server weiterleiten */
  169. IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
  170. /* im Channel bekannt machen */
  171. IRC_WriteStrChannelPrefix( Client, chan, target, false, "JOIN :%s", channame );
  172. if( modes[1] )
  173. {
  174. /* Modes im Channel bekannt machen */
  175. IRC_WriteStrChannelPrefix( Client, chan, target, false, "MODE %s +%s %s", channame, &modes[1], Client_ID( target ));
  176. }
  177. if( Client_Type( Client ) == CLIENT_USER )
  178. {
  179. /* an Client bestaetigen */
  180. IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
  181. /* Send topic to client, if any */
  182. topic = Channel_Topic(chan);
  183. if (*topic) {
  184. IRC_WriteStrClient(Client, RPL_TOPIC_MSG,
  185. Client_ID(Client), channame, topic);
  186. #ifndef STRICT_RFC
  187. IRC_WriteStrClient(Client, RPL_TOPICSETBY_MSG,
  188. Client_ID(Client), channame,
  189. Channel_TopicWho(chan),
  190. Channel_TopicTime(chan));
  191. #endif
  192. }
  193. /* Mitglieder an Client Melden */
  194. IRC_Send_NAMES( Client, chan );
  195. IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan ));
  196. }
  197. /* next channel? */
  198. channame = channame_ptr;
  199. if (channame) {
  200. channame++;
  201. channame_ptr = strchr(channame, ',');
  202. if (channame_ptr) *channame_ptr = '\0';
  203. if (key_ptr) {
  204. key = ++key_ptr;
  205. key_ptr = strchr(key, ',');
  206. if (key_ptr) *key_ptr = '\0';
  207. }
  208. }
  209. }
  210. return CONNECTED;
  211. } /* IRC_JOIN */
  212. GLOBAL bool
  213. IRC_PART( CLIENT *Client, REQUEST *Req )
  214. {
  215. CLIENT *target;
  216. char *chan;
  217. assert( Client != NULL );
  218. assert( Req != NULL );
  219. /* Falsche Anzahl Parameter? */
  220. if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  221. /* Wer ist der Absender? */
  222. if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
  223. else target = Client;
  224. if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  225. /* Channel-Namen durchgehen */
  226. chan = strtok( Req->argv[0], "," );
  227. while( chan )
  228. {
  229. if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
  230. {
  231. /* naechsten Namen ermitteln */
  232. chan = strtok( NULL, "," );
  233. continue;
  234. }
  235. /* naechsten Namen ermitteln */
  236. chan = strtok( NULL, "," );
  237. }
  238. return CONNECTED;
  239. } /* IRC_PART */
  240. GLOBAL bool
  241. IRC_TOPIC( CLIENT *Client, REQUEST *Req )
  242. {
  243. CHANNEL *chan;
  244. CLIENT *from;
  245. char *topic;
  246. bool r;
  247. assert( Client != NULL );
  248. assert( Req != NULL );
  249. /* Falsche Anzahl Parameter? */
  250. if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  251. if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
  252. else from = Client;
  253. if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  254. /* Welcher Channel? */
  255. chan = Channel_Search( Req->argv[0] );
  256. if( ! chan ) return IRC_WriteStrClient( from, ERR_NOSUCHCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
  257. /* Ist der User Mitglied in dem Channel? */
  258. if( ! Channel_IsMemberOf( chan, from )) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
  259. if( Req->argc == 1 )
  260. {
  261. /* Request actual topic */
  262. topic = Channel_Topic(chan);
  263. if (*topic) {
  264. r = IRC_WriteStrClient(from, RPL_TOPIC_MSG,
  265. Client_ID(Client), Channel_Name(chan), topic);
  266. #ifndef STRICT_RFC
  267. r = IRC_WriteStrClient(from, RPL_TOPICSETBY_MSG,
  268. Client_ID(Client), Channel_Name(chan),
  269. Channel_TopicWho(chan),
  270. Channel_TopicTime(chan));
  271. #endif
  272. return r;
  273. }
  274. else
  275. return IRC_WriteStrClient(from, RPL_NOTOPIC_MSG,
  276. Client_ID(from), Channel_Name(chan));
  277. }
  278. if( strchr( Channel_Modes( chan ), 't' ))
  279. {
  280. /* Topic Lock. Ist der User ein Channel Operator? */
  281. if( ! strchr( Channel_UserModes( chan, from ), 'o' )) return IRC_WriteStrClient( from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( from ), Channel_Name( chan ));
  282. }
  283. /* Set new topic */
  284. Channel_SetTopic(chan, from, Req->argv[1]);
  285. Log(LOG_DEBUG, "User \"%s\" set topic on \"%s\": %s",
  286. Client_Mask(from), Channel_Name(chan),
  287. Req->argv[1][0] ? Req->argv[1] : "<none>");
  288. /* im Channel bekannt machen und an Server weiterleiten */
  289. IRC_WriteStrServersPrefix( Client, from, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
  290. IRC_WriteStrChannelPrefix( Client, chan, from, false, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
  291. if( Client_Type( Client ) == CLIENT_USER ) return IRC_WriteStrClientPrefix( Client, Client, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
  292. else return CONNECTED;
  293. } /* IRC_TOPIC */
  294. /**
  295. * Handler for the IRC "LIST" command.
  296. * This implementation handles the local case as well as the forwarding of the
  297. * LIST command to other servers in the IRC network.
  298. */
  299. GLOBAL bool
  300. IRC_LIST( CLIENT *Client, REQUEST *Req )
  301. {
  302. char *pattern;
  303. CHANNEL *chan;
  304. CLIENT *from, *target;
  305. assert( Client != NULL );
  306. assert( Req != NULL );
  307. /* Bad number of prameters? */
  308. if( Req->argc > 2 )
  309. return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG,
  310. Client_ID( Client ), Req->command );
  311. if( Req->argc > 0 )
  312. pattern = strtok( Req->argv[0], "," );
  313. else
  314. pattern = "*";
  315. /* Get sender from prefix, if any */
  316. if( Client_Type( Client ) == CLIENT_SERVER )
  317. from = Client_Search( Req->prefix );
  318. else
  319. from = Client;
  320. if( ! from )
  321. return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG,
  322. Client_ID( Client ), Req->prefix );
  323. if( Req->argc == 2 )
  324. {
  325. /* Forward to other server? */
  326. target = Client_Search( Req->argv[1] );
  327. if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
  328. return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG,
  329. Client_ID( Client ), Req->argv[1] );
  330. if( target != Client_ThisServer( ))
  331. {
  332. /* Target is indeed an other server, forward it! */
  333. return IRC_WriteStrClientPrefix( target, from,
  334. "LIST %s :%s", Client_ID( from ),
  335. Req->argv[1] );
  336. }
  337. }
  338. while( pattern )
  339. {
  340. /* Loop through all the channels */
  341. chan = Channel_First( );
  342. while( chan )
  343. {
  344. /* Check search pattern */
  345. if( Match( pattern, Channel_Name( chan )))
  346. {
  347. /* Gotcha! */
  348. if( ! strchr( Channel_Modes( chan ), 's' ) ||
  349. Channel_IsMemberOf( chan, from ))
  350. {
  351. if( ! IRC_WriteStrClient( from,
  352. RPL_LIST_MSG, Client_ID( from ),
  353. Channel_Name( chan ),
  354. Channel_MemberCount( chan ),
  355. Channel_Topic( chan )))
  356. return DISCONNECTED;
  357. }
  358. }
  359. chan = Channel_Next( chan );
  360. }
  361. /* Get next name ... */
  362. if( Req->argc > 0 )
  363. pattern = strtok( NULL, "," );
  364. else
  365. pattern = NULL;
  366. }
  367. return IRC_WriteStrClient( from, RPL_LISTEND_MSG, Client_ID( from ));
  368. } /* IRC_LIST */
  369. GLOBAL bool
  370. IRC_CHANINFO( CLIENT *Client, REQUEST *Req )
  371. {
  372. char modes_add[COMMAND_LEN], l[16], *ptr;
  373. CLIENT *from;
  374. CHANNEL *chan;
  375. int arg_topic;
  376. assert( Client != NULL );
  377. assert( Req != NULL );
  378. /* Bad number of parameters? */
  379. if(( Req->argc < 2 ) || ( Req->argc == 4 ) || ( Req->argc > 5 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  380. /* Compatibility kludge */
  381. if( Req->argc == 5 ) arg_topic = 4;
  382. else if( Req->argc == 3 ) arg_topic = 2;
  383. else arg_topic = -1;
  384. /* Search origin */
  385. from = Client_Search( Req->prefix );
  386. if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  387. /* Search or create channel */
  388. chan = Channel_Search( Req->argv[0] );
  389. if( ! chan ) chan = Channel_Create( Req->argv[0] );
  390. if( ! chan ) return CONNECTED;
  391. if( Req->argv[1][0] == '+' )
  392. {
  393. ptr = Channel_Modes( chan );
  394. if( ! *ptr )
  395. {
  396. /* OK, this channel doesn't have modes jet, set the received ones: */
  397. Channel_SetModes( chan, &Req->argv[1][1] );
  398. if( Req->argc == 5 )
  399. {
  400. if( strchr( Channel_Modes( chan ), 'k' )) Channel_SetKey( chan, Req->argv[2] );
  401. if( strchr( Channel_Modes( chan ), 'l' )) Channel_SetMaxUsers( chan, atol( Req->argv[3] ));
  402. }
  403. else
  404. {
  405. /* Delete modes which we never want to inherit */
  406. Channel_ModeDel( chan, 'l' );
  407. Channel_ModeDel( chan, 'k' );
  408. }
  409. strcpy( modes_add, "" );
  410. ptr = Channel_Modes( chan );
  411. while( *ptr )
  412. {
  413. if( *ptr == 'l' )
  414. {
  415. snprintf( l, sizeof( l ), " %ld", Channel_MaxUsers( chan ));
  416. strlcat( modes_add, l, sizeof( modes_add ));
  417. }
  418. if( *ptr == 'k' )
  419. {
  420. strlcat( modes_add, " ", sizeof( modes_add ));
  421. strlcat( modes_add, Channel_Key( chan ), sizeof( modes_add ));
  422. }
  423. ptr++;
  424. }
  425. /* Inform members of this channel */
  426. IRC_WriteStrChannelPrefix( Client, chan, from, false, "MODE %s +%s%s", Req->argv[0], Channel_Modes( chan ), modes_add );
  427. }
  428. }
  429. else Log( LOG_WARNING, "CHANINFO: invalid MODE format ignored!" );
  430. if( arg_topic > 0 )
  431. {
  432. /* We got a topic */
  433. ptr = Channel_Topic( chan );
  434. if(( ! *ptr ) && ( Req->argv[arg_topic][0] ))
  435. {
  436. /* OK, there is no topic jet */
  437. Channel_SetTopic(chan, Client, Req->argv[arg_topic]);
  438. IRC_WriteStrChannelPrefix(Client, chan, from, false,
  439. "TOPIC %s :%s", Req->argv[0], Channel_Topic(chan));
  440. }
  441. }
  442. /* Forward CHANINFO to other serevrs */
  443. 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] );
  444. else if( Req->argc == 3 ) IRC_WriteStrServersPrefixFlag( Client, from, 'C', "CHANINFO %s %s :%s", Req->argv[0], Req->argv[1], Req->argv[2] );
  445. else IRC_WriteStrServersPrefixFlag( Client, from, 'C', "CHANINFO %s %s", Req->argv[0], Req->argv[1] );
  446. return CONNECTED;
  447. } /* IRC_CHANINFO */
  448. /* -eof- */