irc-write.c 13 KB

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