numeric.c 9.5 KB

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