diff options
| author | Alexander Barton <alex@barton.de> | 2008-08-17 17:29:41 +0200 |
|---|---|---|
| committer | Alexander Barton <alex@barton.de> | 2008-09-23 11:53:16 +0200 |
| commit | 178f9cbdac3bbeb58600268791916f3bfbcbd958 (patch) | |
| tree | 49326b3c973925a89733d2271e00f97c2d75a921 /src | |
| parent | 6356418ae5fd66f94abda78f1ae67bbc7a59b0e4 (diff) | |
| download | ngircd-178f9cbdac3bbeb58600268791916f3bfbcbd958.tar.gz ngircd-178f9cbdac3bbeb58600268791916f3bfbcbd958.zip | |
Announce IRC services in the network.
This patch - introduces a new server flag "S" to indicate that the server can handle the SERVICE command (on server links), - implements the IRC command "SERVICE" for server-server links, - uses the "SERVICE" command to announce IRC services when a new server connects to it, - and fixes the Send_Message() function to let it send messages to services using a "target mask". If the remote server doesn't indicate that it can handle the "SERVICE" command (it has not set the "S" flag), services are announced as regular users as before.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ngircd/defines.h | 2 | ||||
| -rw-r--r-- | src/ngircd/irc-login.c | 97 | ||||
| -rw-r--r-- | src/ngircd/irc.c | 3 | ||||
| -rw-r--r-- | src/ngircd/numeric.c | 13 |
4 files changed, 104 insertions, 11 deletions
diff --git a/src/ngircd/defines.h b/src/ngircd/defines.h index cccf48b4..7abe6419 100644 --- a/src/ngircd/defines.h +++ b/src/ngircd/defines.h @@ -82,7 +82,7 @@ protocol, see doc/Protocol.txt */ #ifdef IRCPLUS -# define IRCPLUSFLAGS "CHL" /* Standard IRC+ flags */ +# define IRCPLUSFLAGS "CHLS" /* Standard IRC+ flags */ #endif #define STARTUP_DELAY 1 /* Delay outgoing connections n seconds diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index c189228a..943612ed 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -464,17 +464,25 @@ IRC_USER(CLIENT * Client, REQUEST * Req) /** - * Service registration. - * ngIRCd does not support services at the moment, so this function is a - * dummy that returns ERR_ERRONEUSNICKNAME on each call. + * Handler for the IRC command "SERVICE". + * This function implements IRC Services registration using the SERVICE command + * defined in RFC 2812 3.1.6 and RFC 2813 4.1.4. + * At the moment ngIRCd doesn't support directly linked services, so this + * function returns ERR_ERRONEUSNICKNAME when the SERVICE command has not been + * received from a peer server. */ GLOBAL bool IRC_SERVICE(CLIENT *Client, REQUEST *Req) { + CLIENT *c, *intr_c; + char *nick, *user, *host, *info, *modes, *ptr; + int token, hops; + assert(Client != NULL); assert(Req != NULL); - if (Client_Type(Client) != CLIENT_GOTPASS) + if (Client_Type(Client) != CLIENT_GOTPASS && + Client_Type(Client) != CLIENT_SERVER) return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG, Client_ID(Client)); @@ -482,8 +490,74 @@ IRC_SERVICE(CLIENT *Client, REQUEST *Req) return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); - return IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, + if (Client_Type(Client) != CLIENT_SERVER) + return IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID(Client), Req->argv[0]); + + /* Bad number of parameters? */ + if (Req->argc != 6) + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), Req->command); + + nick = Req->argv[0]; + user = NULL; host = NULL; + token = atoi(Req->argv[1]); + hops = atoi(Req->argv[4]); + info = Req->argv[5]; + + /* Validate service name ("nick name") */ + c = Client_Search(nick); + if(c) { + /* Nick name collission: disconnect (KILL) both clients! */ + Log(LOG_ERR, "Server %s introduces already registered service \"%s\"!", + Client_ID(Client), nick); + Kill_Nick(nick, "Nick collision"); + return CONNECTED; + } + + /* Get the server to which the service is connected */ + intr_c = Client_GetFromToken(Client, token); + if (! intr_c) { + Log(LOG_ERR, "Server %s introduces service \"%s\" on unknown server!?", + Client_ID(Client), nick); + Kill_Nick(nick, "Unknown server"); + return CONNECTED; + } + + /* Get user and host name */ + ptr = strchr(nick, '@'); + if (ptr) { + *ptr = '\0'; + host = ++ptr; + } + if (!host) + host = Client_Hostname(intr_c); + ptr = strchr(nick, '!'); + if (ptr) { + *ptr = '\0'; + user = ++ptr; + } + if (!user) + user = nick; + + /* According to RFC 2812/2813 parameter 4 <type> "is currently reserved + * for future usage"; but we use it to transfer the modes and check + * that the first character is a '+' sign and ignore it otherwise. */ + modes = (Req->argv[3][0] == '+') ? ++Req->argv[3] : ""; + + c = Client_NewRemoteUser(intr_c, nick, hops, user, host, + token, modes, info, true); + if (! c) { + /* Couldn't create client structure, so KILL the service to + * keep network status consistent ... */ + Log(LOG_ALERT, "Can't create client structure! (on connection %d)", + Client_Conn(Client)); + Kill_Nick(nick, "Server error"); + return CONNECTED; + } + + Introduce_Client(Client, c, CLIENT_SERVICE); + return CONNECTED; } /* IRC_SERVICE */ @@ -782,8 +856,17 @@ cb_introduceClient(CLIENT *To, CLIENT *Prefix, void *data) Conn_WriteStr(conn, ":%s MODE %s +%s", Client_ID(c), Client_ID(c), modes); } else { - /* RFC 2813 mode: one combined NICK command */ - IRC_WriteStrClientPrefix(To, Prefix, + /* RFC 2813 mode: one combined NICK or SERVICE command */ + if (Client_Type(c) == CLIENT_SERVICE + && strchr(Client_Flags(To), 'S')) + IRC_WriteStrClientPrefix(To, Prefix, + "SERVICE %s %d * +%s %d :%s", + Client_Mask(c), + Client_MyToken(Client_Introducer(c)), + Client_Modes(c), Client_Hops(c) + 1, + Client_Info(c)); + else + IRC_WriteStrClientPrefix(To, Prefix, "NICK %s %d %s %s %d +%s :%s", Client_ID(c), Client_Hops(c) + 1, user, host, diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 0bfb3eed..47f86528 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -400,7 +400,8 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) } for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) { - if (Client_Type(cl) != CLIENT_USER) + if (Client_Type(cl) != CLIENT_USER && + Client_Type(cl) != CLIENT_SERVICE) continue; if (nick != NULL && host != NULL) { if (strcmp(nick, Client_ID(cl)) == 0 && diff --git a/src/ngircd/numeric.c b/src/ngircd/numeric.c index 927989db..ab647665 100644 --- a/src/ngircd/numeric.c +++ b/src/ngircd/numeric.c @@ -100,8 +100,17 @@ Announce_User(CLIENT * Client, CLIENT * User) } return CONNECTED; } else { - /* RFC 2813 mode: one combined NICK command */ - return IRC_WriteStrClient(Client, "NICK %s %d %s %s %d +%s :%s", + /* RFC 2813 mode: one combined NICK or SERVICE command */ + if (Client_Type(User) == CLIENT_SERVICE + && strchr(Client_Flags(Client), 'S')) + return IRC_WriteStrClient(Client, + "SERVICE %s %d * +%s %d :%s", Client_Mask(User), + Client_MyToken(Client_Introducer(User)), + Client_Modes(User), Client_Hops(User) + 1, + Client_Info(User)); + else + return IRC_WriteStrClient(Client, + "NICK %s %d %s %s %d +%s :%s", Client_ID(User), Client_Hops(User) + 1, Client_User(User), Client_Hostname(User), Client_MyToken(Client_Introducer(User)), |