ignore MODE -z but allow MODE +z
[srvx.git] / src / proto-p10.c
index 6509fabb6cf61151cf8e541de3aa513e1bece9e3..d2f20a07796bc67e1e11ca0059e2fdd6383200bd 100644 (file)
@@ -294,7 +294,7 @@ static const char *his_servercomment;
 static struct channelList dead_channels;
 
 /* These correspond to 1 << X:      012345678901234567 */
-const char irc_user_mode_chars[] = "o iw dkgn        I";
+const char irc_user_mode_chars[] = "o iw dkgn    x   I";
 
 static struct userNode *AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, unsigned long timestamp, const char *realip);
 
@@ -655,11 +655,11 @@ void
 irc_gline(struct server *srv, struct gline *gline)
 {
     if (gline->lastmod)
-        putsock("%s " P10_GLINE " %s +%s %lu %lu :%s",
-                self->numeric, (srv ? srv->numeric : "*"), gline->target, (unsigned long)(gline->expires-now), (unsigned long)gline->lastmod, gline->reason);
+        putsock("%s " P10_GLINE " %s +%s %lu %lu %lu :%s",
+                self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires, gline->lastmod, gline->lifetime, gline->reason);
     else
         putsock("%s " P10_GLINE " %s +%s %lu :%s",
-                self->numeric, (srv ? srv->numeric : "*"), gline->target, (unsigned long)(gline->expires-now), gline->reason);
+                self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires, gline->reason);
 }
 
 void
@@ -674,7 +674,7 @@ irc_settime(const char *srv_name_mask, unsigned long new_time)
 void
 irc_ungline(const char *mask)
 {
-    putsock("%s " P10_GLINE " * -%s", self->numeric, mask);
+    putsock("%s " P10_GLINE " * -%s %lu", self->numeric, mask, now);
 }
 
 /* Return negative if *(struct modeNode**)pa is "less than" pb,
@@ -1494,10 +1494,13 @@ static CMD_FUNC(cmd_num_topic)
 static CMD_FUNC(cmd_num_gline)
 {
     unsigned long lastmod;
+    unsigned long lifetime;
+
     if (argc < 6)
         return 0;
     lastmod = (argc > 5) ? strtoul(argv[5], NULL, 0) : 0;
-    gline_add(origin, argv[3], atoi(argv[4])-now, argv[argc - 1], now, lastmod, 0);
+    lifetime = (argc > 6) ? strtoul(argv[6], NULL, 0) : 0;
+    gline_add(origin, argv[3], atoi(argv[4])-now, argv[argc - 1], now, lastmod, lifetime, 0);
     return 1;
 }
 
@@ -1612,15 +1615,22 @@ static CMD_FUNC(cmd_away)
 
 static CMD_FUNC(cmd_gline)
 {
+#define PASTWATCH (5*365*24*3600)
     unsigned long lastmod;
+    unsigned long lifetime;
+    unsigned long expiration;
 
     if (argc < 3)
         return 0;
     if (argv[2][0] == '+') {
         if (argc < 5)
             return 0;
-        lastmod = (argc > 5) ? strtoul(argv[5], NULL, 0) : 0;
-        gline_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, lastmod, 0);
+        expiration = strtoul(argv[3], NULL, 10);
+        if (expiration < now - PASTWATCH)
+            expiration += now;
+        lastmod = (argc > 5) ? strtoul(argv[4], NULL, 10) : 0;
+        lifetime = (argc > 6) ? strtoul(argv[5], NULL, 10) : 0;
+        gline_add(origin, argv[2]+1, expiration - now, argv[argc-1], now, lastmod, lifetime, 0);
         return 1;
     } else if (argv[2][0] == '-') {
         gline_remove(argv[2]+1, 0);
@@ -1641,6 +1651,23 @@ static CMD_FUNC(cmd_svsnick)
     return 1;
 }
 
+static CMD_FUNC(cmd_time)
+{
+    extern int clock_skew;
+    char buf[MAXLEN];
+    struct userNode *who;
+    time_t when;
+
+    who = GetUserH(origin);
+    if (!who)
+        return 0;
+
+    when = time(NULL);
+    strftime(buf, sizeof(buf), "%a %b %d %Y -- %H:%M %z", localtime(&when));
+    irc_numeric(who, 391, "%s %lu %d :%s", self->name, now, clock_skew, buf);
+    return 1;
+}
+
 void
 free_user(struct userNode *user)
 {
@@ -1780,6 +1807,8 @@ init_parse(void)
     dict_insert(irc_func_dict, TOK_VERSION, cmd_version);
     dict_insert(irc_func_dict, CMD_ADMIN, cmd_admin);
     dict_insert(irc_func_dict, TOK_ADMIN, cmd_admin);
+    dict_insert(irc_func_dict, CMD_TIME, cmd_time);
+    dict_insert(irc_func_dict, TOK_TIME, cmd_time);
 
     /* In P10, DESTRUCT doesn't do anything except be broadcast to servers.
      * Apparently to obliterate channels from any servers that think they
@@ -2322,6 +2351,7 @@ void mod_usermode(struct userNode *user, const char *mode_change) {
                 char mask[MAXLEN];
                 char *host, *ident;
                 unsigned int ii;
+
                 for (ii=0; (*word != ' ') && (*word != '\0'); )
                     mask[ii++] = *word++;
                 mask[ii] = 0;
@@ -2335,6 +2365,7 @@ void mod_usermode(struct userNode *user, const char *mode_change) {
                     ident = NULL;
                     host = mask;
                 }
+                user->modes |= FLAGS_HIDDEN_HOST;
                 assign_fakehost(user, host, ident, 0, 0);
             }
             break;
@@ -2396,12 +2427,14 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un
         case 's': do_chan_mode(MODE_SECRET); break;
         case 't': do_chan_mode(MODE_TOPICLIMIT); break;
         case 'z':
-          if (!(flags & MCP_REGISTERED)) {
-              do_chan_mode(MODE_REGISTERED);
-          } else {
-              mod_chanmode_free(change);
-              return NULL;
-          }
+          if (!(flags & MCP_REGISTERED) && (!(flags & MCP_IGN_REGISTERED) || add)) {
+            do_chan_mode(MODE_REGISTERED);
++          } else if (flags & MCP_IGN_REGISTERED) {
++           /* ignore the modechange but continue parsing */
+           } else {
+            mod_chanmode_free(change);
+            return NULL;
+           }
           break;
 #undef do_chan_mode
         case 'l':
@@ -2431,6 +2464,8 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un
             }
             break;
         case 'U':
+            if (flags & MCP_NO_APASS)
+                goto error;
             if (add)
             {
                 if ((in_arg >= argc)
@@ -2447,6 +2482,8 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un
             }
             break;
         case 'A':
+            if (flags & MCP_NO_APASS)
+                goto error;
             if (add) {
                 if ((in_arg >= argc)
                     || keyncpy(change->new_apass, modes[in_arg++], sizeof(change->new_apass)))
@@ -2697,6 +2734,9 @@ char *
 mod_chanmode_format(struct mod_chanmode *change, char *outbuff)
 {
     unsigned int used = 0;
+    unsigned int args_used = 0;
+    char args[MAXLEN];
+
     assert(change->argc <= change->alloc_argc);
     if (change->modes_clear) {
         outbuff[used++] = '-';
@@ -2732,61 +2772,14 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff)
         DO_MODE_CHAR(NOCOLORS, 'c');
         DO_MODE_CHAR(NOCTCPS, 'C');
         DO_MODE_CHAR(REGISTERED, 'z');
+        DO_MODE_CHAR(LIMIT, 'l'), args_used += sprintf(args + args_used, " %d", change->new_limit);
+        DO_MODE_CHAR(KEY, 'k'), args_used += sprintf(args + args_used, " %s", change->new_key);
+        DO_MODE_CHAR(UPASS, 'U'), args_used += sprintf(args + args_used, " %s", change->new_upass);
+        DO_MODE_CHAR(APASS, 'A'), args_used += sprintf(args + args_used, " %s", change->new_apass);
 #undef DO_MODE_CHAR
-        switch (change->modes_set & (MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS)) {
-        /* Doing this implementation has been a pain in the arse, I hope I didn't forget a possible combination */
-        case MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS:
-            used += sprintf(outbuff+used, "lkAU %d %s %s %s", change->new_limit, change->new_key, change->new_apass, change->new_upass);
-            break;
-
-        case MODE_KEY|MODE_LIMIT|MODE_APASS:
-            used += sprintf(outbuff+used, "lkA %d %s %s", change->new_limit, change->new_key, change->new_apass);
-            break;
-        case MODE_KEY|MODE_LIMIT|MODE_UPASS:
-            used += sprintf(outbuff+used, "lkU %d %s %s", change->new_limit, change->new_key, change->new_upass);
-            break;
-        case MODE_KEY|MODE_APASS|MODE_UPASS:
-            used += sprintf(outbuff+used, "kAU %s %s %s", change->new_key, change->new_apass, change->new_upass);
-            break;
-
-        case MODE_KEY|MODE_APASS:
-            used += sprintf(outbuff+used, "kA %s %s", change->new_key, change->new_apass);
-            break;
-        case MODE_KEY|MODE_UPASS:
-            used += sprintf(outbuff+used, "kU %s %s", change->new_key, change->new_upass);
-            break;
-        case MODE_KEY|MODE_LIMIT:
-            used += sprintf(outbuff+used, "lk %d %s", change->new_limit, change->new_key);
-            break;
-        case MODE_LIMIT|MODE_UPASS:
-            used += sprintf(outbuff+used, "lU %d %s", change->new_limit, change->new_upass);
-            break;
-        case MODE_LIMIT|MODE_APASS:
-            used += sprintf(outbuff+used, "lA %d %s", change->new_limit, change->new_apass);
-            break;
-        case MODE_APASS|MODE_UPASS:
-            used += sprintf(outbuff+used, "AU %s %s", change->new_apass, change->new_upass);
-            break;
-
-        case MODE_LIMIT|MODE_APASS|MODE_UPASS:
-            used += sprintf(outbuff+used, "lAU %d %s %s", change->new_limit, change->new_apass, change->new_upass);
-            break;
-
-        case MODE_APASS:
-            used += sprintf(outbuff+used, "A %s", change->new_apass);
-            break;
-        case MODE_UPASS:
-            used += sprintf(outbuff+used, "U %s", change->new_upass);
-            break;
-        case MODE_KEY:
-            used += sprintf(outbuff+used, "k %s", change->new_key);
-            break;
-        case MODE_LIMIT:
-            used += sprintf(outbuff+used, "l %d", change->new_limit);
-            break;
-        }
     }
-    outbuff[used] = 0;
+    args[args_used] = '\0';
+    strcpy(outbuff + used, args);
     return outbuff;
 }