irc-write.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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. * Sending IRC commands over the network
  15. */
  16. #include "imp.h"
  17. #include <assert.h>
  18. #ifdef PROTOTYPES
  19. # include <stdarg.h>
  20. #else
  21. # include <varargs.h>
  22. #endif
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include "defines.h"
  26. #include "conn-func.h"
  27. #include "channel.h"
  28. #include "exp.h"
  29. #include "irc-write.h"
  30. #define SEND_TO_USER 1
  31. #define SEND_TO_SERVER 2
  32. static const char *Get_Prefix PARAMS((CLIENT *Target, CLIENT *Client));
  33. static void cb_writeStrServersPrefixFlag PARAMS((CLIENT *Client,
  34. CLIENT *Prefix, void *Buffer));
  35. static void Send_Marked_Connections PARAMS((CLIENT *Prefix, const char *Buffer));
  36. /**
  37. * Send an error message to a client and enforce a penalty time.
  38. *
  39. * @param Client The target client.
  40. * @param Format Format string.
  41. * @return CONNECTED or DISCONNECTED.
  42. */
  43. #ifdef PROTOTYPES
  44. GLOBAL bool
  45. IRC_WriteErrClient( CLIENT *Client, const char *Format, ... )
  46. #else
  47. GLOBAL bool
  48. IRC_WriteErrClient( Client, Format, va_alist )
  49. CLIENT *Client;
  50. const char *Format;
  51. va_dcl
  52. #endif
  53. {
  54. char buffer[1000];
  55. va_list ap;
  56. assert(Client != NULL);
  57. assert(Format != NULL);
  58. #ifdef PROTOTYPES
  59. va_start(ap, Format);
  60. #else
  61. va_start(ap);
  62. #endif
  63. vsnprintf(buffer, 1000, Format, ap);
  64. va_end(ap);
  65. IRC_SetPenalty(Client, 2);
  66. return IRC_WriteStrClientPrefix(Client, Client_ThisServer(),
  67. "%s", buffer);
  68. }
  69. /**
  70. * Send a message to a client.
  71. *
  72. * @param Client The target client.
  73. * @param Format Format string.
  74. * @return CONNECTED or DISCONNECTED.
  75. */
  76. #ifdef PROTOTYPES
  77. GLOBAL bool
  78. IRC_WriteStrClient( CLIENT *Client, const char *Format, ... )
  79. #else
  80. GLOBAL bool
  81. IRC_WriteStrClient( Client, Format, va_alist )
  82. CLIENT *Client;
  83. const char *Format;
  84. va_dcl
  85. #endif
  86. {
  87. char buffer[1000];
  88. va_list ap;
  89. assert(Client != NULL);
  90. assert(Format != NULL);
  91. #ifdef PROTOTYPES
  92. va_start(ap, Format);
  93. #else
  94. va_start(ap);
  95. #endif
  96. vsnprintf(buffer, 1000, Format, ap);
  97. va_end(ap);
  98. return IRC_WriteStrClientPrefix(Client, Client_ThisServer(),
  99. "%s", buffer);
  100. }
  101. /**
  102. * Send a message to a client using a specific prefix.
  103. *
  104. * @param Client The target client.
  105. * @param Prefix The prefix to use.
  106. * @param Format Format string.
  107. * @return CONNECTED or DISCONNECTED.
  108. */
  109. #ifdef PROTOTYPES
  110. GLOBAL bool
  111. IRC_WriteStrClientPrefix(CLIENT *Client, CLIENT *Prefix, const char *Format, ...)
  112. #else
  113. GLOBAL bool
  114. IRC_WriteStrClientPrefix(Client, Prefix, Format, va_alist)
  115. CLIENT *Client;
  116. CLIENT *Prefix;
  117. const char *Format;
  118. va_dcl
  119. #endif
  120. {
  121. /* send text to local and remote clients */
  122. char buffer[1000];
  123. va_list ap;
  124. assert( Client != NULL );
  125. assert( Format != NULL );
  126. assert( Prefix != NULL );
  127. #ifdef PROTOTYPES
  128. va_start( ap, Format );
  129. #else
  130. va_start( ap );
  131. #endif
  132. vsnprintf( buffer, 1000, Format, ap );
  133. va_end( ap );
  134. return Conn_WriteStr(Client_Conn(Client_NextHop(Client)), ":%s %s",
  135. Get_Prefix(Client_NextHop(Client), Prefix), buffer);
  136. }
  137. /**
  138. * Send a message to all client in a channel.
  139. *
  140. * The message is only sent once per remote server.
  141. *
  142. * @param Client The sending client, excluded while forwarding the message.
  143. * @param Channel The target channel.
  144. * @param Remote If not set, the message is sent to local clients only.
  145. * @param Format Format string.
  146. */
  147. #ifdef PROTOTYPES
  148. GLOBAL void
  149. IRC_WriteStrChannel(CLIENT *Client, CHANNEL *Chan, bool Remote,
  150. const char *Format, ...)
  151. #else
  152. GLOBAL void
  153. IRC_WriteStrChannel(Client, Chan, Remote, Format, va_alist)
  154. CLIENT *Client;
  155. CHANNEL *Chan;
  156. bool Remote;
  157. const char *Format;
  158. va_dcl
  159. #endif
  160. {
  161. char buffer[1000];
  162. va_list ap;
  163. assert( Client != NULL );
  164. assert( Format != NULL );
  165. #ifdef PROTOTYPES
  166. va_start( ap, Format );
  167. #else
  168. va_start( ap );
  169. #endif
  170. vsnprintf( buffer, 1000, Format, ap );
  171. va_end( ap );
  172. IRC_WriteStrChannelPrefix(Client, Chan, Client_ThisServer(),
  173. Remote, "%s", buffer);
  174. }
  175. /**
  176. * Send a message to all client in a channel using a specific prefix.
  177. *
  178. * The message is only sent once per remote server.
  179. *
  180. * @param Client The sending client, excluded while forwarding the message.
  181. * @param Channel The target channel.
  182. * @param Prefix The prefix to use.
  183. * @param Remote If not set, the message is sent to local clients only.
  184. * @param Format Format string.
  185. */
  186. #ifdef PROTOTYPES
  187. GLOBAL void
  188. IRC_WriteStrChannelPrefix(CLIENT *Client, CHANNEL *Chan, CLIENT *Prefix,
  189. bool Remote, const char *Format, ...)
  190. #else
  191. GLOBAL void
  192. IRC_WriteStrChannelPrefix(Client, Chan, Prefix, Remote, Format, va_alist)
  193. CLIENT *Client;
  194. CHANNEL *Chan;
  195. CLIENT *Prefix;
  196. bool Remote;
  197. const char *Format;
  198. va_dcl
  199. #endif
  200. {
  201. char buffer[1000];
  202. CL2CHAN *cl2chan;
  203. CONN_ID conn;
  204. CLIENT *c;
  205. va_list ap;
  206. assert( Client != NULL );
  207. assert( Chan != NULL );
  208. assert( Prefix != NULL );
  209. assert( Format != NULL );
  210. #ifdef PROTOTYPES
  211. va_start( ap, Format );
  212. #else
  213. va_start( ap );
  214. #endif
  215. vsnprintf( buffer, 1000, Format, ap );
  216. va_end( ap );
  217. Conn_ClearFlags( );
  218. cl2chan = Channel_FirstMember( Chan );
  219. while(cl2chan) {
  220. c = Channel_GetClient( cl2chan );
  221. if (!Remote) {
  222. if (Client_Conn(c) <= NONE)
  223. c = NULL;
  224. else if(Client_Type(c) == CLIENT_SERVER)
  225. c = NULL;
  226. }
  227. if(c)
  228. c = Client_NextHop(c);
  229. if(c && c != Client) {
  230. /* Ok, another Client */
  231. conn = Client_Conn(c);
  232. if (Client_Type(c) == CLIENT_SERVER)
  233. Conn_SetFlag(conn, SEND_TO_SERVER);
  234. else
  235. Conn_SetFlag(conn, SEND_TO_USER);
  236. }
  237. cl2chan = Channel_NextMember(Chan, cl2chan);
  238. }
  239. Send_Marked_Connections(Prefix, buffer);
  240. }
  241. /**
  242. * Send a message to all the servers in the network.
  243. *
  244. * @param Client The sending client, excluded while forwarding the message.
  245. * @param Format Format string.
  246. */
  247. #ifdef PROTOTYPES
  248. GLOBAL void
  249. IRC_WriteStrServers(CLIENT *ExceptOf, const char *Format, ...)
  250. #else
  251. GLOBAL void
  252. IRC_WriteStrServers(ExceptOf, Format, va_alist)
  253. CLIENT *ExceptOf;
  254. const char *Format;
  255. va_dcl
  256. #endif
  257. {
  258. char buffer[1000];
  259. va_list ap;
  260. assert( Format != NULL );
  261. #ifdef PROTOTYPES
  262. va_start( ap, Format );
  263. #else
  264. va_start( ap );
  265. #endif
  266. vsnprintf( buffer, 1000, Format, ap );
  267. va_end( ap );
  268. IRC_WriteStrServersPrefix(ExceptOf, Client_ThisServer(), "%s", buffer);
  269. }
  270. /**
  271. * Send a message to all the servers in the network using a specific prefix.
  272. *
  273. * @param Client The sending client, excluded while forwarding the message.
  274. * @param Prefix The prefix to use.
  275. * @param Format Format string.
  276. */
  277. #ifdef PROTOTYPES
  278. GLOBAL void
  279. IRC_WriteStrServersPrefix(CLIENT *ExceptOf, CLIENT *Prefix,
  280. const char *Format, ...)
  281. #else
  282. GLOBAL void
  283. IRC_WriteStrServersPrefix(ExceptOf, Prefix, Format, va_alist)
  284. CLIENT *ExceptOf;
  285. CLIENT *Prefix;
  286. const char *Format;
  287. va_dcl
  288. #endif
  289. {
  290. char buffer[1000];
  291. va_list ap;
  292. assert( Format != NULL );
  293. assert( Prefix != NULL );
  294. #ifdef PROTOTYPES
  295. va_start( ap, Format );
  296. #else
  297. va_start( ap );
  298. #endif
  299. vsnprintf( buffer, 1000, Format, ap );
  300. va_end( ap );
  301. IRC_WriteStrServersPrefixFlag( ExceptOf, Prefix, '\0', "%s", buffer );
  302. }
  303. /**
  304. * Send a message to all the servers in the network using a specific prefix
  305. * and matching a "client flag".
  306. *
  307. * @param Client The sending client, excluded while forwarding the message.
  308. * @param Prefix The prefix to use.
  309. * @param Flag Client flag that must be set on the target.
  310. * @param Format Format string.
  311. */
  312. #ifdef PROTOTYPES
  313. GLOBAL void
  314. IRC_WriteStrServersPrefixFlag(CLIENT *ExceptOf, CLIENT *Prefix, char Flag,
  315. const char *Format, ...)
  316. #else
  317. GLOBAL void
  318. IRC_WriteStrServersPrefixFlag(ExceptOf, Prefix, Flag, Format, va_alist)
  319. CLIENT *ExceptOf;
  320. CLIENT *Prefix;
  321. char Flag;
  322. const char *Format;
  323. va_dcl
  324. #endif
  325. {
  326. char buffer[1000];
  327. va_list ap;
  328. assert( Format != NULL );
  329. assert( Prefix != NULL );
  330. #ifdef PROTOTYPES
  331. va_start( ap, Format );
  332. #else
  333. va_start( ap );
  334. #endif
  335. vsnprintf( buffer, 1000, Format, ap );
  336. va_end( ap );
  337. IRC_WriteStrServersPrefixFlag_CB(ExceptOf, Prefix, Flag,
  338. cb_writeStrServersPrefixFlag, buffer);
  339. }
  340. /**
  341. * Send a message to all the servers in the network using a specific prefix
  342. * and matching a "client flag" using a callback function.
  343. *
  344. * @param Client The sending client, excluded while forwarding the message.
  345. * @param Prefix The prefix to use.
  346. * @param Flag Client flag that must be set on the target.
  347. * @param callback Callback function.
  348. * @param Format Format string.
  349. */
  350. GLOBAL void
  351. IRC_WriteStrServersPrefixFlag_CB(CLIENT *ExceptOf, CLIENT *Prefix, char Flag,
  352. void (*callback)(CLIENT *, CLIENT *, void *), void *cb_data)
  353. {
  354. CLIENT *c;
  355. c = Client_First();
  356. while(c) {
  357. if (Client_Type(c) == CLIENT_SERVER && Client_Conn(c) > NONE &&
  358. c != Client_ThisServer() && c != ExceptOf) {
  359. /* Found a target server, do the flags match? */
  360. if (Flag == '\0' || Client_HasFlag(c, Flag))
  361. callback(c, Prefix, cb_data);
  362. }
  363. c = Client_Next(c);
  364. }
  365. }
  366. /**
  367. * Send a message to all "related" clients.
  368. *
  369. * Related clients are the one that share one ore more channels with the client
  370. * sending this message.
  371. *
  372. * The message is only sent once per remote server.
  373. *
  374. * @param Client The sending client, excluded while forwarding the message.
  375. * @param Prefix The prefix to use.
  376. * @param Remote If not set, the message is sent to local clients only.
  377. * @param Format Format string.
  378. */
  379. #ifdef PROTOTYPES
  380. GLOBAL void
  381. IRC_WriteStrRelatedPrefix(CLIENT *Client, CLIENT *Prefix, bool Remote,
  382. const char *Format, ...)
  383. #else
  384. GLOBAL void
  385. IRC_WriteStrRelatedPrefix(Client, Prefix, Remote, Format, va_alist)
  386. CLIENT *Client;
  387. CLIENT *Prefix;
  388. bool Remote;
  389. const char *Format;
  390. va_dcl
  391. #endif
  392. {
  393. CL2CHAN *chan_cl2chan, *cl2chan;
  394. char buffer[1000];
  395. CHANNEL *chan;
  396. CONN_ID conn;
  397. va_list ap;
  398. CLIENT *c;
  399. assert( Client != NULL );
  400. assert( Prefix != NULL );
  401. assert( Format != NULL );
  402. #ifdef PROTOTYPES
  403. va_start( ap, Format );
  404. #else
  405. va_start( ap );
  406. #endif
  407. vsnprintf( buffer, 1000, Format, ap );
  408. va_end( ap );
  409. Conn_ClearFlags( );
  410. chan_cl2chan = Channel_FirstChannelOf( Client );
  411. while( chan_cl2chan )
  412. {
  413. chan = Channel_GetChannel( chan_cl2chan );
  414. cl2chan = Channel_FirstMember( chan );
  415. while( cl2chan )
  416. {
  417. c = Channel_GetClient( cl2chan );
  418. if( ! Remote )
  419. {
  420. if( Client_Conn( c ) <= NONE ) c = NULL;
  421. else if( Client_Type( c ) == CLIENT_SERVER ) c = NULL;
  422. }
  423. if( c ) c = Client_NextHop( c );
  424. if( c && ( c != Client ))
  425. {
  426. conn = Client_Conn( c );
  427. if( Client_Type( c ) == CLIENT_SERVER ) Conn_SetFlag( conn, SEND_TO_SERVER );
  428. else Conn_SetFlag( conn, SEND_TO_USER );
  429. }
  430. cl2chan = Channel_NextMember( chan, cl2chan );
  431. }
  432. chan_cl2chan = Channel_NextChannelOf( Client, chan_cl2chan );
  433. }
  434. Send_Marked_Connections(Prefix, buffer);
  435. } /* IRC_WriteStrRelatedPrefix */
  436. /**
  437. * Send WALLOPS message.
  438. *
  439. * @param Client The sending client, excluded while forwarding the message.
  440. * @param From The (remote) sender of the message.
  441. * @param Format Format string.
  442. */
  443. #ifdef PROTOTYPES
  444. GLOBAL void
  445. IRC_SendWallops(CLIENT *Client, CLIENT *From, const char *Format, ...)
  446. #else
  447. GLOBAL void
  448. IRC_SendWallops(Client, From, Format, va_alist )
  449. CLIENT *Client;
  450. CLIENT *From;
  451. const char *Format;
  452. va_dcl
  453. #endif
  454. {
  455. va_list ap;
  456. char msg[1000];
  457. CLIENT *to;
  458. #ifdef PROTOTYPES
  459. va_start(ap, Format);
  460. #else
  461. va_start(ap);
  462. #endif
  463. vsnprintf(msg, 1000, Format, ap);
  464. va_end(ap);
  465. for (to=Client_First(); to != NULL; to=Client_Next(to)) {
  466. if (Client_Conn(to) == NONE) /* no local connection */
  467. continue;
  468. switch (Client_Type(to)) {
  469. case CLIENT_USER:
  470. if (Client_HasMode(to, 'w'))
  471. IRC_WriteStrClientPrefix(to, From,
  472. "WALLOPS :%s", msg);
  473. break;
  474. case CLIENT_SERVER:
  475. if (to != Client)
  476. IRC_WriteStrClientPrefix(to, From,
  477. "WALLOPS :%s", msg);
  478. break;
  479. }
  480. }
  481. } /* IRC_SendWallops */
  482. /**
  483. * Set a "penalty time" for an IRC client.
  484. *
  485. * Note: penalty times are never set for server links or remote clients!
  486. *
  487. * @param Client The client.
  488. * @param Seconds The additional "penalty time" to enforce.
  489. */
  490. GLOBAL void
  491. IRC_SetPenalty(CLIENT *Client, time_t Seconds)
  492. {
  493. CONN_ID c;
  494. assert(Client != NULL);
  495. assert(Seconds > 0);
  496. if (Client_Type(Client) == CLIENT_SERVER)
  497. return;
  498. c = Client_Conn(Client);
  499. if (c <= NONE)
  500. return;
  501. Conn_SetPenalty(c, Seconds);
  502. } /* IRC_SetPenalty */
  503. static const char *
  504. Get_Prefix(CLIENT *Target, CLIENT *Client)
  505. {
  506. assert (Target != NULL);
  507. assert (Client != NULL);
  508. if (Client_Type(Target) == CLIENT_SERVER)
  509. return Client_ID(Client);
  510. else
  511. return Client_MaskCloaked(Client);
  512. } /* Get_Prefix */
  513. static void
  514. cb_writeStrServersPrefixFlag(CLIENT *Client, CLIENT *Prefix, void *Buffer)
  515. {
  516. IRC_WriteStrClientPrefix(Client, Prefix, "%s", Buffer);
  517. } /* cb_writeStrServersPrefixFlag */
  518. /**
  519. * Send a message to all marked connections using a specific prefix.
  520. *
  521. * @param Prefix The prefix to use.
  522. * @param Buffer The message to send.
  523. */
  524. static void
  525. Send_Marked_Connections(CLIENT *Prefix, const char *Buffer)
  526. {
  527. CONN_ID conn;
  528. assert(Prefix != NULL);
  529. assert(Buffer != NULL);
  530. conn = Conn_First();
  531. while (conn != NONE) {
  532. if (Conn_Flag(conn) == SEND_TO_SERVER)
  533. Conn_WriteStr(conn, ":%s %s",
  534. Client_ID(Prefix), Buffer);
  535. else if (Conn_Flag(conn) == SEND_TO_USER)
  536. Conn_WriteStr(conn, ":%s %s",
  537. Client_MaskCloaked(Prefix), Buffer);
  538. conn = Conn_Next(conn);
  539. }
  540. }
  541. /* -eof- */