irc-write.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2018 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 ExceptOf 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. */
  345. GLOBAL void
  346. IRC_WriteStrServersPrefixFlag_CB(CLIENT *ExceptOf, CLIENT *Prefix, char Flag,
  347. void (*callback)(CLIENT *, CLIENT *, void *), void *cb_data)
  348. {
  349. CLIENT *c;
  350. c = Client_First();
  351. while(c) {
  352. if (Client_Type(c) == CLIENT_SERVER && Client_Conn(c) > NONE &&
  353. c != Client_ThisServer() && c != ExceptOf) {
  354. /* Found a target server, do the flags match? */
  355. if (Flag == '\0' || Client_HasFlag(c, Flag))
  356. callback(c, Prefix, cb_data);
  357. }
  358. c = Client_Next(c);
  359. }
  360. }
  361. /**
  362. * Send a message to all "related" clients.
  363. *
  364. * Related clients are the one that share one ore more channels with the client
  365. * sending this message.
  366. *
  367. * The message is only sent once per remote server.
  368. *
  369. * @param Client The sending client, excluded while forwarding the message.
  370. * @param Prefix The prefix to use.
  371. * @param Remote If not set, the message is sent to local clients only.
  372. * @param Format Format string.
  373. */
  374. #ifdef PROTOTYPES
  375. GLOBAL void
  376. IRC_WriteStrRelatedPrefix(CLIENT *Client, CLIENT *Prefix, bool Remote,
  377. const char *Format, ...)
  378. #else
  379. GLOBAL void
  380. IRC_WriteStrRelatedPrefix(Client, Prefix, Remote, Format, va_alist)
  381. CLIENT *Client;
  382. CLIENT *Prefix;
  383. bool Remote;
  384. const char *Format;
  385. va_dcl
  386. #endif
  387. {
  388. CL2CHAN *chan_cl2chan, *cl2chan;
  389. char buffer[1000];
  390. CHANNEL *chan;
  391. CONN_ID conn;
  392. va_list ap;
  393. CLIENT *c;
  394. assert( Client != NULL );
  395. assert( Prefix != NULL );
  396. assert( Format != NULL );
  397. #ifdef PROTOTYPES
  398. va_start( ap, Format );
  399. #else
  400. va_start( ap );
  401. #endif
  402. vsnprintf(buffer, sizeof(buffer), Format, ap);
  403. va_end( ap );
  404. Conn_ClearFlags( );
  405. chan_cl2chan = Channel_FirstChannelOf( Client );
  406. while( chan_cl2chan )
  407. {
  408. chan = Channel_GetChannel( chan_cl2chan );
  409. cl2chan = Channel_FirstMember( chan );
  410. while( cl2chan )
  411. {
  412. c = Channel_GetClient( cl2chan );
  413. if( ! Remote )
  414. {
  415. if( Client_Conn( c ) <= NONE ) c = NULL;
  416. else if( Client_Type( c ) == CLIENT_SERVER ) c = NULL;
  417. }
  418. if( c ) c = Client_NextHop( c );
  419. if( c && ( c != Client ))
  420. {
  421. conn = Client_Conn( c );
  422. if( Client_Type( c ) == CLIENT_SERVER ) Conn_SetFlag( conn, SEND_TO_SERVER );
  423. else Conn_SetFlag( conn, SEND_TO_USER );
  424. }
  425. cl2chan = Channel_NextMember( chan, cl2chan );
  426. }
  427. chan_cl2chan = Channel_NextChannelOf( Client, chan_cl2chan );
  428. }
  429. Send_Marked_Connections(Prefix, buffer);
  430. } /* IRC_WriteStrRelatedPrefix */
  431. /**
  432. * Send WALLOPS message.
  433. *
  434. * @param Client The sending client, excluded while forwarding the message.
  435. * @param From The (remote) sender of the message.
  436. * @param Format Format string.
  437. */
  438. #ifdef PROTOTYPES
  439. GLOBAL void
  440. IRC_SendWallops(CLIENT *Client, CLIENT *From, const char *Format, ...)
  441. #else
  442. GLOBAL void
  443. IRC_SendWallops(Client, From, Format, va_alist )
  444. CLIENT *Client;
  445. CLIENT *From;
  446. const char *Format;
  447. va_dcl
  448. #endif
  449. {
  450. va_list ap;
  451. char msg[1000];
  452. CLIENT *to;
  453. #ifdef PROTOTYPES
  454. va_start(ap, Format);
  455. #else
  456. va_start(ap);
  457. #endif
  458. vsnprintf(msg, sizeof(msg), Format, ap);
  459. va_end(ap);
  460. for (to=Client_First(); to != NULL; to=Client_Next(to)) {
  461. if (Client_Conn(to) == NONE) /* no local connection */
  462. continue;
  463. switch (Client_Type(to)) {
  464. case CLIENT_USER:
  465. if (Client_HasMode(to, 'w'))
  466. IRC_WriteStrClientPrefix(to, From,
  467. "WALLOPS :%s", msg);
  468. break;
  469. case CLIENT_SERVER:
  470. if (to != Client)
  471. IRC_WriteStrClientPrefix(to, From,
  472. "WALLOPS :%s", msg);
  473. break;
  474. }
  475. }
  476. } /* IRC_SendWallops */
  477. /**
  478. * Set a "penalty time" for an IRC client.
  479. *
  480. * Note: penalty times are never set for server links or remote clients!
  481. *
  482. * @param Client The client.
  483. * @param Seconds The additional "penalty time" to enforce.
  484. */
  485. GLOBAL void
  486. IRC_SetPenalty(CLIENT *Client, time_t Seconds)
  487. {
  488. CONN_ID c;
  489. assert(Client != NULL);
  490. assert(Seconds > 0);
  491. if (Client_Type(Client) == CLIENT_SERVER)
  492. return;
  493. c = Client_Conn(Client);
  494. if (c <= NONE)
  495. return;
  496. Conn_SetPenalty(c, Seconds);
  497. } /* IRC_SetPenalty */
  498. static const char *
  499. Get_Prefix(CLIENT *Target, CLIENT *Client)
  500. {
  501. assert (Target != NULL);
  502. assert (Client != NULL);
  503. if (Client_Type(Target) == CLIENT_SERVER)
  504. return Client_ID(Client);
  505. else
  506. return Client_MaskCloaked(Client);
  507. } /* Get_Prefix */
  508. static void
  509. cb_writeStrServersPrefixFlag(CLIENT *Client, CLIENT *Prefix, void *Buffer)
  510. {
  511. IRC_WriteStrClientPrefix(Client, Prefix, "%s", Buffer);
  512. } /* cb_writeStrServersPrefixFlag */
  513. /**
  514. * Send a message to all marked connections using a specific prefix.
  515. *
  516. * @param Prefix The prefix to use.
  517. * @param Buffer The message to send.
  518. */
  519. static void
  520. Send_Marked_Connections(CLIENT *Prefix, const char *Buffer)
  521. {
  522. CONN_ID conn;
  523. assert(Prefix != NULL);
  524. assert(Buffer != NULL);
  525. conn = Conn_First();
  526. while (conn != NONE) {
  527. if (Conn_Flag(conn) == SEND_TO_SERVER)
  528. Conn_WriteStr(conn, ":%s %s",
  529. Client_ID(Prefix), Buffer);
  530. else if (Conn_Flag(conn) == SEND_TO_USER)
  531. Conn_WriteStr(conn, ":%s %s",
  532. Client_MaskCloaked(Prefix), Buffer);
  533. conn = Conn_Next(conn);
  534. }
  535. }
  536. /* -eof- */