numeric.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2008 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. #include "portab.h"
  12. /**
  13. * @file
  14. * Handlers for IRC numerics sent to the server
  15. */
  16. #include "imp.h"
  17. #include <assert.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "defines.h"
  22. #include "conn.h"
  23. #include "conf.h"
  24. #include "conn.h"
  25. #include "conn-func.h"
  26. #include "channel.h"
  27. #include "class.h"
  28. #include "irc-write.h"
  29. #include "lists.h"
  30. #include "log.h"
  31. #include "messages.h"
  32. #include "parse.h"
  33. #include "exp.h"
  34. #include "numeric.h"
  35. /**
  36. * Announce a channel and its users in the network.
  37. */
  38. static bool
  39. Announce_Channel(CLIENT *Client, CHANNEL *Chan)
  40. {
  41. CL2CHAN *cl2chan;
  42. CLIENT *cl;
  43. char str[LINE_LEN], *ptr;
  44. bool njoin, xop;
  45. /* Check features of remote server */
  46. njoin = Conn_Options(Client_Conn(Client)) & CONN_RFC1459 ? false : true;
  47. xop = strchr(Client_Flags(Client), 'X') ? true : false;
  48. /* Get all the members of this channel */
  49. cl2chan = Channel_FirstMember(Chan);
  50. snprintf(str, sizeof(str), "NJOIN %s :", Channel_Name(Chan));
  51. while (cl2chan) {
  52. cl = Channel_GetClient(cl2chan);
  53. assert(cl != NULL);
  54. if (njoin) {
  55. /* RFC 2813: send NJOIN with nicknames and modes
  56. * (if user is channel operator or has voice) */
  57. if (str[strlen(str) - 1] != ':')
  58. strlcat(str, ",", sizeof(str));
  59. /* Prepare user prefix (ChanOp, voiced, ...) */
  60. if (xop && strchr(Channel_UserModes(Chan, cl), 'q'))
  61. strlcat(str, "~", sizeof(str));
  62. if (xop && strchr(Channel_UserModes(Chan, cl), 'a'))
  63. strlcat(str, "&", sizeof(str));
  64. if (strchr(Channel_UserModes(Chan, cl), 'o'))
  65. strlcat(str, "@", sizeof(str));
  66. if (xop && strchr(Channel_UserModes(Chan, cl), 'h'))
  67. strlcat(str, "%", sizeof(str));
  68. if (strchr(Channel_UserModes(Chan, cl), 'v'))
  69. strlcat(str, "+", sizeof(str));
  70. strlcat(str, Client_ID(cl), sizeof(str));
  71. /* Send the data if the buffer is "full" */
  72. if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 8)) {
  73. if (!IRC_WriteStrClient(Client, "%s", str))
  74. return DISCONNECTED;
  75. snprintf(str, sizeof(str), "NJOIN %s :",
  76. Channel_Name(Chan));
  77. }
  78. } else {
  79. /* RFC 1459: no NJOIN, send JOIN and MODE */
  80. if (!IRC_WriteStrClientPrefix(Client, cl, "JOIN %s",
  81. Channel_Name(Chan)))
  82. return DISCONNECTED;
  83. ptr = Channel_UserModes(Chan, cl);
  84. while (*ptr) {
  85. if (!IRC_WriteStrClientPrefix(Client, cl,
  86. "MODE %s +%c %s",
  87. Channel_Name(Chan), ptr[0],
  88. Client_ID(cl)))
  89. return DISCONNECTED;
  90. ptr++;
  91. }
  92. }
  93. cl2chan = Channel_NextMember(Chan, cl2chan);
  94. }
  95. /* Data left in the buffer? */
  96. if (str[strlen(str) - 1] != ':') {
  97. /* Yes, send it ... */
  98. if (!IRC_WriteStrClient(Client, "%s", str))
  99. return DISCONNECTED;
  100. }
  101. return CONNECTED;
  102. } /* Announce_Channel */
  103. /**
  104. * Announce new server in the network
  105. * @param Client New server
  106. * @param Server Existing server in the network
  107. */
  108. static bool
  109. Announce_Server(CLIENT * Client, CLIENT * Server)
  110. {
  111. CLIENT *c;
  112. if (Client_Conn(Server) > NONE) {
  113. /* Announce the new server to the one already registered
  114. * which is directly connected to the local server */
  115. if (!IRC_WriteStrClient
  116. (Server, "SERVER %s %d %d :%s", Client_ID(Client),
  117. Client_Hops(Client) + 1, Client_MyToken(Client),
  118. Client_Info(Client)))
  119. return DISCONNECTED;
  120. }
  121. if (Client_Hops(Server) == 1)
  122. c = Client_ThisServer();
  123. else
  124. c = Client_TopServer(Server);
  125. /* Inform new server about the one already registered in the network */
  126. return IRC_WriteStrClientPrefix(Client, c, "SERVER %s %d %d :%s",
  127. Client_ID(Server), Client_Hops(Server) + 1,
  128. Client_MyToken(Server), Client_Info(Server));
  129. } /* Announce_Server */
  130. /**
  131. * Announce existing user to a new server
  132. * @param Client New server
  133. * @param User Existing user in the network
  134. */
  135. static bool
  136. Announce_User(CLIENT * Client, CLIENT * User)
  137. {
  138. CONN_ID conn;
  139. char *modes;
  140. conn = Client_Conn(Client);
  141. if (Conn_Options(conn) & CONN_RFC1459) {
  142. /* RFC 1459 mode: separate NICK and USER commands */
  143. if (! Conn_WriteStr(conn, "NICK %s :%d",
  144. Client_ID(User), Client_Hops(User) + 1))
  145. return DISCONNECTED;
  146. if (! Conn_WriteStr(conn, ":%s USER %s %s %s :%s",
  147. Client_ID(User), Client_User(User),
  148. Client_Hostname(User),
  149. Client_ID(Client_Introducer(User)),
  150. Client_Info(User)))
  151. return DISCONNECTED;
  152. modes = Client_Modes(User);
  153. if (modes[0]) {
  154. return Conn_WriteStr(conn, ":%s MODE %s +%s",
  155. Client_ID(User), Client_ID(User),
  156. modes);
  157. }
  158. } else {
  159. /* RFC 2813 mode: one combined NICK or SERVICE command */
  160. if (Client_Type(User) == CLIENT_SERVICE
  161. && strchr(Client_Flags(Client), 'S')) {
  162. if (!IRC_WriteStrClient(Client,
  163. "SERVICE %s %d * +%s %d :%s",
  164. Client_Mask(User),
  165. Client_MyToken(Client_Introducer(User)),
  166. Client_Modes(User), Client_Hops(User) + 1,
  167. Client_Info(User)))
  168. return DISCONNECTED;
  169. } else {
  170. if (!IRC_WriteStrClient(Client,
  171. "NICK %s %d %s %s %d +%s :%s",
  172. Client_ID(User), Client_Hops(User) + 1,
  173. Client_User(User), Client_Hostname(User),
  174. Client_MyToken(Client_Introducer(User)),
  175. Client_Modes(User), Client_Info(User)))
  176. return DISCONNECTED;
  177. }
  178. }
  179. if (strchr(Client_Flags(Client), 'M')) {
  180. /* Synchronize metadata */
  181. if (Client_HostnameCloaked(User)) {
  182. if (!IRC_WriteStrClient(Client,
  183. "METADATA %s cloakhost :%s",
  184. Client_ID(User),
  185. Client_HostnameCloaked(User)))
  186. return DISCONNECTED;
  187. }
  188. }
  189. return CONNECTED;
  190. } /* Announce_User */
  191. #ifdef IRCPLUS
  192. /**
  193. * Synchronize invite, ban, G- and K-Line lists between servers.
  194. *
  195. * @param Client New server.
  196. * @return CONNECTED or DISCONNECTED.
  197. */
  198. static bool
  199. Synchronize_Lists(CLIENT * Client)
  200. {
  201. CHANNEL *c;
  202. struct list_head *head;
  203. struct list_elem *elem;
  204. assert(Client != NULL);
  205. /* g-lines */
  206. head = Class_GetList(CLASS_GLINE);
  207. elem = Lists_GetFirst(head);
  208. while (elem) {
  209. if (!IRC_WriteStrClient(Client, "GLINE %s %ld :%s",
  210. Lists_GetMask(elem),
  211. Lists_GetValidity(elem) - time(NULL),
  212. Lists_GetReason(elem)))
  213. return DISCONNECTED;
  214. elem = Lists_GetNext(elem);
  215. }
  216. c = Channel_First();
  217. while (c) {
  218. /* ban list */
  219. head = Channel_GetListBans(c);
  220. elem = Lists_GetFirst(head);
  221. while (elem) {
  222. if (!IRC_WriteStrClient(Client, "MODE %s +b %s",
  223. Channel_Name(c),
  224. Lists_GetMask(elem))) {
  225. return DISCONNECTED;
  226. }
  227. elem = Lists_GetNext(elem);
  228. }
  229. /* invite list */
  230. head = Channel_GetListInvites(c);
  231. elem = Lists_GetFirst(head);
  232. while (elem) {
  233. if (!IRC_WriteStrClient(Client, "MODE %s +I %s",
  234. Channel_Name(c),
  235. Lists_GetMask(elem))) {
  236. return DISCONNECTED;
  237. }
  238. elem = Lists_GetNext(elem);
  239. }
  240. c = Channel_Next(c);
  241. }
  242. return CONNECTED;
  243. }
  244. /**
  245. * Send CHANINFO commands to a new server (inform it about existing channels).
  246. * @param Client New server
  247. * @param Chan Channel
  248. */
  249. static bool
  250. Send_CHANINFO(CLIENT * Client, CHANNEL * Chan)
  251. {
  252. char *modes, *topic;
  253. bool has_k, has_l;
  254. #ifdef DEBUG
  255. Log(LOG_DEBUG, "Sending CHANINFO commands ...");
  256. #endif
  257. modes = Channel_Modes(Chan);
  258. topic = Channel_Topic(Chan);
  259. if (!*modes && !*topic)
  260. return CONNECTED;
  261. has_k = strchr(modes, 'k') != NULL;
  262. has_l = strchr(modes, 'l') != NULL;
  263. /* send CHANINFO */
  264. if (!has_k && !has_l) {
  265. if (!*topic) {
  266. /* "CHANINFO <chan> +<modes>" */
  267. return IRC_WriteStrClient(Client, "CHANINFO %s +%s",
  268. Channel_Name(Chan), modes);
  269. }
  270. /* "CHANINFO <chan> +<modes> :<topic>" */
  271. return IRC_WriteStrClient(Client, "CHANINFO %s +%s :%s",
  272. Channel_Name(Chan), modes, topic);
  273. }
  274. /* "CHANINFO <chan> +<modes> <key> <limit> :<topic>" */
  275. return IRC_WriteStrClient(Client, "CHANINFO %s +%s %s %lu :%s",
  276. Channel_Name(Chan), modes,
  277. has_k ? Channel_Key(Chan) : "*",
  278. has_l ? Channel_MaxUsers(Chan) : 0, topic);
  279. } /* Send_CHANINFO */
  280. #endif /* IRCPLUS */
  281. /**
  282. * Handle ENDOFMOTD (376) numeric and login remote server.
  283. * The peer is either an IRC server (no IRC+ protocol), or we got the
  284. * ENDOFMOTD numeric from an IRC+ server. We have to register the new server.
  285. */
  286. GLOBAL bool
  287. IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req)
  288. {
  289. int max_hops, i;
  290. CLIENT *c;
  291. CHANNEL *chan;
  292. Client_SetType(Client, CLIENT_SERVER);
  293. Log(LOG_NOTICE | LOG_snotice,
  294. "Server \"%s\" registered (connection %d, 1 hop - direct link).",
  295. Client_ID(Client), Client_Conn(Client));
  296. /* Get highest hop count */
  297. max_hops = 0;
  298. c = Client_First();
  299. while (c) {
  300. if (Client_Hops(c) > max_hops)
  301. max_hops = Client_Hops(c);
  302. c = Client_Next(c);
  303. }
  304. /* Inform the new server about all other servers, and announce the
  305. * new server to all the already registered ones. Important: we have
  306. * to do this "in order" and can't introduce servers of which the
  307. * "toplevel server" isn't known already. */
  308. for (i = 0; i < (max_hops + 1); i++) {
  309. for (c = Client_First(); c != NULL; c = Client_Next(c)) {
  310. if (Client_Type(c) != CLIENT_SERVER)
  311. continue; /* not a server */
  312. if (Client_Hops(c) != i)
  313. continue; /* not actual "nesting level" */
  314. if (c == Client || c == Client_ThisServer())
  315. continue; /* that's us or the peer! */
  316. if (!Announce_Server(Client, c))
  317. return DISCONNECTED;
  318. }
  319. }
  320. /* Announce all the users to the new server */
  321. c = Client_First();
  322. while (c) {
  323. if (Client_Type(c) == CLIENT_USER ||
  324. Client_Type(c) == CLIENT_SERVICE) {
  325. if (!Announce_User(Client, c))
  326. return DISCONNECTED;
  327. }
  328. c = Client_Next(c);
  329. }
  330. /* Announce all channels to the new server */
  331. chan = Channel_First();
  332. while (chan) {
  333. if (Channel_IsLocal(chan)) {
  334. chan = Channel_Next(chan);
  335. continue;
  336. }
  337. #ifdef IRCPLUS
  338. /* Send CHANINFO if the peer supports it */
  339. if (strchr(Client_Flags(Client), 'C')) {
  340. if (!Send_CHANINFO(Client, chan))
  341. return DISCONNECTED;
  342. }
  343. #endif
  344. if (!Announce_Channel(Client, chan))
  345. return DISCONNECTED;
  346. /* Get next channel ... */
  347. chan = Channel_Next(chan);
  348. }
  349. #ifdef IRCPLUS
  350. if (strchr(Client_Flags(Client), 'L')) {
  351. LogDebug("Synchronizing INVITE- and BAN-lists ...");
  352. if (!Synchronize_Lists(Client))
  353. return DISCONNECTED;
  354. }
  355. #endif
  356. if (!IRC_WriteStrClient(Client, "PING :%s",
  357. Client_ID(Client_ThisServer())))
  358. return DISCONNECTED;
  359. return CONNECTED;
  360. } /* IRC_Num_ENDOFMOTD */
  361. /**
  362. * Handle ISUPPORT (005) numeric.
  363. */
  364. GLOBAL bool
  365. IRC_Num_ISUPPORT(CLIENT * Client, REQUEST * Req)
  366. {
  367. int i;
  368. char *key, *value;
  369. for (i = 1; i < Req->argc - 1; i++) {
  370. key = Req->argv[i];
  371. value = strchr(key, '=');
  372. if (value)
  373. *value++ = '\0';
  374. else
  375. value = "";
  376. if (strcmp("NICKLEN", key) == 0) {
  377. if ((unsigned int)atol(value) == Conf_MaxNickLength - 1)
  378. continue;
  379. /* Nickname length settings are different! */
  380. Log(LOG_ERR,
  381. "Peer uses incompatible nickname length (%d/%d)! Disconnecting ...",
  382. Conf_MaxNickLength - 1, atoi(value));
  383. Conn_Close(Client_Conn(Client),
  384. "Incompatible nickname length",
  385. NULL, false);
  386. return DISCONNECTED;
  387. }
  388. }
  389. return CONNECTED;
  390. } /* IRC_Num_ISUPPORT */
  391. /* -eof- */