numeric.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2007 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. * Handlers for IRC numerics sent to the server
  12. */
  13. #include "portab.h"
  14. static char UNUSED id[] = "$Id: numeric.c,v 1.1 2007/11/21 12:20:32 alex Exp $";
  15. #include "imp.h"
  16. #include <assert.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include "defines.h"
  21. #include "resolve.h"
  22. #include "conn.h"
  23. #include "conf.h"
  24. #include "conn.h"
  25. #include "client.h"
  26. #include "channel.h"
  27. #include "irc-write.h"
  28. #include "lists.h"
  29. #include "log.h"
  30. #include "messages.h"
  31. #include "parse.h"
  32. #include "exp.h"
  33. #include "numeric.h"
  34. /**
  35. * Announce new server in the network
  36. * @param Client New server
  37. * @param Server Existing server in the network
  38. */
  39. static bool
  40. Announce_Server(CLIENT * Client, CLIENT * Server)
  41. {
  42. CLIENT *c;
  43. if (Client_Conn(Server) > NONE) {
  44. /* Announce the new server to the one already registered
  45. * which is directly connected to the local server */
  46. if (!IRC_WriteStrClient
  47. (Server, "SERVER %s %d %d :%s", Client_ID(Client),
  48. Client_Hops(Client) + 1, Client_MyToken(Client),
  49. Client_Info(Client)))
  50. return DISCONNECTED;
  51. }
  52. if (Client_Hops(Server) == 1)
  53. c = Client_ThisServer();
  54. else
  55. c = Client_Introducer(Server);
  56. /* Inform new server about the one already registered in the network */
  57. return IRC_WriteStrClientPrefix(Client, c, "SERVER %s %d %d :%s",
  58. Client_ID(Server), Client_Hops(Server) + 1,
  59. Client_MyToken(Server), Client_Info(Server));
  60. } /* Announce_Server */
  61. /**
  62. * Announce existing user to a new server
  63. * @param Client New server
  64. * @param User Existing user in the network
  65. */
  66. static bool
  67. Announce_User(CLIENT * Client, CLIENT * User)
  68. {
  69. return IRC_WriteStrClient(Client, "NICK %s %d %s %s %d +%s :%s",
  70. Client_ID(User), Client_Hops(User) + 1, Client_User(User),
  71. Client_Hostname(User), Client_MyToken(Client_Introducer(User)),
  72. Client_Modes(User), Client_Info(User));
  73. } /* Announce_User */
  74. #ifdef IRCPLUS
  75. /**
  76. * Synchronize invite and ban lists between servers
  77. * @param Client New server
  78. */
  79. static bool
  80. Synchronize_Lists(CLIENT * Client)
  81. {
  82. CHANNEL *c;
  83. struct list_head *head;
  84. struct list_elem *elem;
  85. assert(Client != NULL);
  86. c = Channel_First();
  87. while (c) {
  88. /* ban list */
  89. head = Channel_GetListBans(c);
  90. elem = Lists_GetFirst(head);
  91. while (elem) {
  92. if (!IRC_WriteStrClient(Client, "MODE %s +b %s",
  93. Channel_Name(c),
  94. Lists_GetMask(elem))) {
  95. return DISCONNECTED;
  96. }
  97. elem = Lists_GetNext(elem);
  98. }
  99. /* invite list */
  100. head = Channel_GetListInvites(c);
  101. elem = Lists_GetFirst(head);
  102. while (elem) {
  103. if (!IRC_WriteStrClient(Client, "MODE %s +I %s",
  104. Channel_Name(c),
  105. Lists_GetMask(elem))) {
  106. return DISCONNECTED;
  107. }
  108. elem = Lists_GetNext(elem);
  109. }
  110. c = Channel_Next(c);
  111. }
  112. return CONNECTED;
  113. }
  114. /**
  115. * Send CHANINFO commands to a new server (inform it about existing channels).
  116. * @param Client New server
  117. * @param Chan Channel
  118. */
  119. static bool
  120. Send_CHANINFO(CLIENT * Client, CHANNEL * Chan)
  121. {
  122. char *modes, *topic;
  123. bool has_k, has_l;
  124. #ifdef DEBUG
  125. Log(LOG_DEBUG, "Sending CHANINFO commands ...");
  126. #endif
  127. modes = Channel_Modes(Chan);
  128. topic = Channel_Topic(Chan);
  129. if (!*modes && !*topic)
  130. return CONNECTED;
  131. has_k = strchr(modes, 'k') != NULL;
  132. has_l = strchr(modes, 'l') != NULL;
  133. /* send CHANINFO */
  134. if (!has_k && !has_l) {
  135. if (!*topic) {
  136. /* "CHANINFO <chan> +<modes>" */
  137. return IRC_WriteStrClient(Client, "CHANINFO %s +%s",
  138. Channel_Name(Chan), modes);
  139. }
  140. /* "CHANINFO <chan> +<modes> :<topic>" */
  141. return IRC_WriteStrClient(Client, "CHANINFO %s +%s :%s",
  142. Channel_Name(Chan), modes, topic);
  143. }
  144. /* "CHANINFO <chan> +<modes> <key> <limit> :<topic>" */
  145. return IRC_WriteStrClient(Client, "CHANINFO %s +%s %s %lu :%s",
  146. Channel_Name(Chan), modes,
  147. has_k ? Channel_Key(Chan) : "*",
  148. has_l ? Channel_MaxUsers(Chan) : 0, topic);
  149. } /* Send_CHANINFO */
  150. #endif /* IRCPLUS */
  151. /**
  152. * Handle ENDOFMOTD (376) numeric and login remote server.
  153. * The peer is either an IRC server (no IRC+ protocol), or we got the
  154. * ENDOFMOTD numeric from an IRC+ server. We have to register the new server.
  155. */
  156. GLOBAL bool
  157. IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req)
  158. {
  159. char str[LINE_LEN];
  160. int max_hops, i;
  161. CLIENT *c, *cl;
  162. CHANNEL *chan;
  163. CL2CHAN *cl2chan;
  164. Client_SetType(Client, CLIENT_SERVER);
  165. Log(LOG_NOTICE | LOG_snotice,
  166. "Server \"%s\" registered (connection %d, 1 hop - direct link).",
  167. Client_ID(Client), Client_Conn(Client));
  168. /* Get highest hop count */
  169. max_hops = 0;
  170. c = Client_First();
  171. while (c) {
  172. if (Client_Hops(c) > max_hops)
  173. max_hops = Client_Hops(c);
  174. c = Client_Next(c);
  175. }
  176. /* Inform the new server about all other servers, and announce the
  177. * new server to all the already registered ones. Important: we have
  178. * to do this "in order" and can't introduce servers of which the
  179. * "toplevel server" isn't known already. */
  180. for (i = 0; i < (max_hops + 1); i++) {
  181. for (c = Client_First(); c != NULL; c = Client_Next(c)) {
  182. if (Client_Type(c) != CLIENT_SERVER)
  183. continue; /* not a server */
  184. if (Client_Hops(c) != i)
  185. continue; /* not actual "nesting level" */
  186. if (c == Client || c == Client_ThisServer())
  187. continue; /* that's us or the peer! */
  188. if (!Announce_Server(Client, c))
  189. return DISCONNECTED;
  190. }
  191. }
  192. /* Announce all the users to the new server */
  193. c = Client_First();
  194. while (c) {
  195. if (Client_Type(c) == CLIENT_USER) {
  196. if (!Announce_User(Client, c))
  197. return DISCONNECTED;
  198. }
  199. c = Client_Next(c);
  200. }
  201. /* Announce all channels to the new server */
  202. chan = Channel_First();
  203. while (chan) {
  204. #ifdef IRCPLUS
  205. /* Send CHANINFO if the peer supports it */
  206. if (strchr(Client_Flags(Client), 'C')) {
  207. if (!Send_CHANINFO(Client, chan))
  208. return DISCONNECTED;
  209. }
  210. #endif
  211. /* Get all the members of this channel */
  212. cl2chan = Channel_FirstMember(chan);
  213. snprintf(str, sizeof(str), "NJOIN %s :", Channel_Name(chan));
  214. while (cl2chan) {
  215. cl = Channel_GetClient(cl2chan);
  216. assert(cl != NULL);
  217. /* Nick name, with modes (if applicable) */
  218. if (str[strlen(str) - 1] != ':')
  219. strlcat(str, ",", sizeof(str));
  220. if (strchr(Channel_UserModes(chan, cl), 'v'))
  221. strlcat(str, "+", sizeof(str));
  222. if (strchr(Channel_UserModes(chan, cl), 'o'))
  223. strlcat(str, "@", sizeof(str));
  224. strlcat(str, Client_ID(cl), sizeof(str));
  225. /* Send the data if the buffer is "full" */
  226. if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 8)) {
  227. if (!IRC_WriteStrClient(Client, "%s", str))
  228. return DISCONNECTED;
  229. snprintf(str, sizeof(str), "NJOIN %s :",
  230. Channel_Name(chan));
  231. }
  232. cl2chan = Channel_NextMember(chan, cl2chan);
  233. }
  234. /* Data left in the buffer? */
  235. if (str[strlen(str) - 1] != ':') {
  236. /* Yes, send it ... */
  237. if (!IRC_WriteStrClient(Client, "%s", str))
  238. return DISCONNECTED;
  239. }
  240. /* Get next channel ... */
  241. chan = Channel_Next(chan);
  242. }
  243. #ifdef IRCPLUS
  244. if (strchr(Client_Flags(Client), 'L')) {
  245. LogDebug("Synchronizing INVITE- and BAN-lists ...");
  246. if (!Synchronize_Lists(Client))
  247. return DISCONNECTED;
  248. }
  249. #endif
  250. return CONNECTED;
  251. } /* IRC_Num_ENDOFMOTD */
  252. /**
  253. * Handle ISUPPORT (005) numeric.
  254. */
  255. GLOBAL bool
  256. IRC_Num_ISUPPORT(CLIENT * Client, REQUEST * Req)
  257. {
  258. int i;
  259. char *key, *value;
  260. for (i = 1; i < Req->argc - 1; i++) {
  261. key = Req->argv[i];
  262. value = strchr(key, '=');
  263. if (value)
  264. *value++ = '\0';
  265. else
  266. value = "";
  267. if (strcmp("NICKLEN", key) == 0) {
  268. if ((unsigned int)atol(value) == Conf_MaxNickLength - 1)
  269. continue;
  270. /* Nick name length settings are different! */
  271. Log(LOG_ERR,
  272. "Peer uses incompatible nick name length (%d/%d)! Disconnecting ...",
  273. Conf_MaxNickLength - 1, atoi(value));
  274. Conn_Close(Client_Conn(Client),
  275. "Incompatible nick name length",
  276. NULL, false);
  277. return DISCONNECTED;
  278. }
  279. }
  280. return CONNECTED;
  281. } /* IRC_Num_ISUPPORT */
  282. /* -eof- */