+/**
+ * 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 &&
+ Client_Type(Client) != CLIENT_SERVER)
+ return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG,
+ Client_ID(Client));
+
+ if (Req->argc != 6)
+ return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+ Client_ID(Client), Req->command);
+
+ 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 */
+
+
+/**
+ * Handler for the IRC command "WEBIRC".
+ * Syntax: WEBIRC <password> <username> <real-hostname> <real-IP-address>
+ */
+GLOBAL bool
+IRC_WEBIRC(CLIENT *Client, REQUEST *Req)
+{
+ /* Exactly 4 parameters are requited */
+ if (Req->argc != 4)
+ return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+ Client_ID(Client), Req->command);
+
+ if (!Conf_WebircPwd[0] || strcmp(Req->argv[0], Conf_WebircPwd) != 0)
+ return IRC_WriteStrClient(Client, ERR_PASSWDMISMATCH_MSG,
+ Client_ID(Client));
+
+ LogDebug("Connection %d: got valid WEBIRC command: user=%s, host=%s, ip=%s",
+ Client_Conn(Client), Req->argv[1], Req->argv[2], Req->argv[3]);
+
+ Client_SetUser(Client, Req->argv[1], true);
+ Client_SetOrigUser(Client, Req->argv[1]);
+ Client_SetHostname(Client, Req->argv[2]);
+ return CONNECTED;
+} /* IRC_WEBIRC */
+
+
+GLOBAL bool
+IRC_QUIT( CLIENT *Client, REQUEST *Req )