]> jfr.im git - irc/quakenet/newserv.git/blobdiff - helpmod2/hcommands.c
Large reorganisation of all Makefiles, including new configure script.
[irc/quakenet/newserv.git] / helpmod2 / hcommands.c
index 61c21552efc122c368b1caecc1bb21b4da62c1bf..56b2574b3667357719ca26a52670f06971ccba28 100644 (file)
@@ -5,10 +5,6 @@
 #include <sys/types.h>
 #include <dirent.h>
 
-#include "../nick/nick.h"
-#include "../channel/channel.h"
-#include "../lib/irc_string.h"
-
 #include "hcommands.h"
 #include "hcommand.h"
 
@@ -354,15 +350,27 @@ static void helpmod_cmd_change_userlevel(huser *sender, hlevel target_level, cha
             {
                 helpmod_reply(sender, returntype, "Cannot change userlevel: Sanity check, you're changing your own userlevel, use #account instead of nick if you really wish to do this");
                 continue;
-            }
-            if (!IsAccount(target_huser->real_user))
-            {
+           }
+
+           if (target_level == H_LAMER)
+           {
+               const char *banmask = hban_ban_string(target_huser->real_user, HBAN_HOST);
+               hban_add(banmask, "Improper user", time(NULL) + HCMD_OUT_DEFAULT, 1);
+               if (!IsAccount(target_huser->real_user))
+               {
+                   helpmod_reply(sender, returntype, "Cannot change userlevel: User '%s' is not authed. Banning user instead.", argv[i]);
+                   continue;
+               }
+           }
+
+           if (!IsAccount(target_huser->real_user))
+           {
                 helpmod_reply(sender, returntype, "Cannot change userlevel: User '%s' is not authed", argv[i]);
                 continue;
             }
 
-            if (target_huser->account == NULL)
-            {
+           if (target_huser->account == NULL)
+           {
                 if (haccount_get_by_name(huser_get_auth(target_huser)) != NULL)
                 {
                     helpmod_reply(sender, returntype, "Cannot change userlevel: Unable to create an account. Account %s already exists", huser_get_auth(target_huser));
@@ -376,12 +384,7 @@ static void helpmod_cmd_change_userlevel(huser *sender, hlevel target_level, cha
 
            helpmod_reply(sender, returntype, "Userlevel changed: User '%s' now has userlevel %s", argv[i], hlevel_name(target_level));
 
-           if (huser_get_level(target_huser) == H_LAMER)
-           {
-               const char *banmask = hban_ban_string(target_huser->real_user, HBAN_HOST);
-                hban_add(banmask, "Improper user", time(NULL) + HCMD_OUT_DEFAULT, 1);
-           }
-           else
+            if (target_level != H_LAMER)
                helpmod_reply(target_huser, NULL, "Your userlevel has been changed, your current userlevel is %s", hlevel_name(target_level));
         }
     }
@@ -390,6 +393,7 @@ static void helpmod_cmd_change_userlevel(huser *sender, hlevel target_level, cha
 /* pseudo commands for the above */
 static void helpmod_cmd_improper (huser *sender, channel* returntype, char* ostr, int argc, char *argv[]) { helpmod_cmd_change_userlevel(sender, H_LAMER, returntype, ostr, argc, argv); }
 static void helpmod_cmd_peon (huser *sender, channel* returntype, char* ostr, int argc, char *argv[]) { helpmod_cmd_change_userlevel(sender, H_PEON, returntype, ostr, argc, argv); }
+static void helpmod_cmd_friend (huser *sender, channel* returntype, char* ostr, int argc, char *argv[]) { helpmod_cmd_change_userlevel(sender, H_FRIEND, returntype, ostr, argc, argv); }
 static void helpmod_cmd_trial (huser *sender, channel* returntype, char* ostr, int argc, char *argv[]) { helpmod_cmd_change_userlevel(sender, H_TRIAL, returntype, ostr, argc, argv); }
 static void helpmod_cmd_staff (huser *sender, channel* returntype, char* ostr, int argc, char *argv[]) { helpmod_cmd_change_userlevel(sender, H_STAFF, returntype, ostr, argc, argv); }
 static void helpmod_cmd_oper (huser *sender, channel* returntype, char* ostr, int argc, char *argv[]) { helpmod_cmd_change_userlevel(sender, H_OPER, returntype, ostr, argc, argv); }
@@ -553,9 +557,16 @@ static void helpmod_cmd_censor (huser *sender, channel* returntype, char* ostr,
            }
 
            pattern = argv[0];
-            SKIP_WORD;
-            if (argc)
-                reason = ostr;
+
+           if (strlen(pattern) == 0)
+           {
+               helpmod_reply(sender, returntype, "Cannot add censor entry: Pattern must be non-empty");
+                return;
+           }
+
+           SKIP_WORD;
+           if (argc && strlen(ostr) > 0)
+               reason = ostr;
             else
                 reason = NULL;
 
@@ -882,7 +893,7 @@ static void helpmod_cmd_term_find_general (huser *sender, channel* returntype, i
         helpmod_reply(sender, returntype, "No term found matching '%s'", argv[0]);
         return;
     }
-    if (returntype != NULL && huser_get_level(sender) > H_PEON)
+    if (returntype != NULL && huser_get_level(sender) >= H_TRIAL)
     {
         HCHANNEL_VERIFY_AUTHORITY(hchan, sender);
 
@@ -1027,7 +1038,7 @@ void helpmod_cmd_term (huser *sender, channel* returntype, char* ostr, int argc,
             }
             if (strregexp(htrm->description->content, pattern) || strregexp(htrm->name->content, pattern))
             {
-                sprintf(buffer+strlen(buffer) /* :) */, "%s(%d) ", htrm->name->content, strlen(htrm->description->content));
+                sprintf(buffer+strlen(buffer) /* :) */, "%s(%u) ", htrm->name->content, (unsigned int)strlen(htrm->description->content));
                 count++;
             }
         }
@@ -1108,7 +1119,7 @@ void helpmod_cmd_term (huser *sender, channel* returntype, char* ostr, int argc,
             helpmod_reply(sender, returntype, "No term found matching '%s'", argv[1]);
             return;
         }
-        if (returntype != NULL && huser_get_level(sender) > H_PEON)
+        if (returntype != NULL && huser_get_level(sender) >= H_TRIAL)
             helpmod_message_channel(hchannel_get_by_channel(returntype), "(%s): %s", htrm->name->content, htrm->description->content);
         else
             helpmod_reply(sender, returntype, "(%s): %s", htrm->name->content, htrm->description->content);
@@ -1573,6 +1584,22 @@ static void helpmod_cmd_out (huser *sender, channel* returntype, char* ostr, int
                SKIP_WORD;
            }
            reason = ostr + 1;
+
+           if (!strncmp(reason, "?? ", 3))
+           { /* obtain reason from hterms */
+               hchannel *hchan = NULL;
+                hterm *new_reason;
+               if (returntype != NULL)
+               { /* if hchan is NULL here then everything is broken already */
+                   hchan = hchannel_get_by_channel(returntype);
+                   new_reason = hterm_get_and_find(hchan->channel_hterms, reason + 3);
+               }
+               else
+                   new_reason = hterm_get_and_find(hterms, reason + 3);
+
+               if (new_reason != NULL)
+                   reason = new_reason->description->content;
+           }
            break;
        }
 
@@ -1607,6 +1634,11 @@ static void helpmod_cmd_everyoneout (huser *sender, channel* returntype, char* o
     hchannel_user **hchanuser;
     char *reason = "clearing channel";
     int autoqueue_tmp = -1;
+    enum
+    {
+       HELPMOD_KICKMODE_ALL,
+        HELPMOD_KICKMODE_UNAUTHED
+    } kickmode = HELPMOD_KICKMODE_ALL;
 
     DEFINE_HCHANNEL;
 
@@ -1619,7 +1651,21 @@ static void helpmod_cmd_everyoneout (huser *sender, channel* returntype, char* o
     }
 
     if (argc)
-        reason = ostr;
+    {
+       if (!ci_strcmp(argv[0], "all"))
+       {
+           kickmode = HELPMOD_KICKMODE_ALL;
+           SKIP_WORD;
+       }
+       else if (!ci_strcmp(argv[0], "unauthed"))
+       {
+            kickmode = HELPMOD_KICKMODE_UNAUTHED;
+            SKIP_WORD;
+       }
+       if (ostr[0] == ':')
+           ostr++;
+       reason = ostr;
+    }
 
     hchan->flags |= H_MAINTAIN_I;
     hchannel_mode_check(hchan);
@@ -1634,10 +1680,13 @@ static void helpmod_cmd_everyoneout (huser *sender, channel* returntype, char* o
 
     while (*hchanuser)
     {
-        if (huser_get_level((*hchanuser)->husr) < H_TRIAL)
-            helpmod_kick(hchan, (*hchanuser)->husr, reason);
-        else
-            hchanuser = &(*hchanuser)->next;
+       if (huser_get_level((*hchanuser)->husr) < H_TRIAL)
+           if (kickmode == HELPMOD_KICKMODE_ALL || (kickmode == HELPMOD_KICKMODE_UNAUTHED && !IsAccount((*hchanuser)->husr->real_user)))
+           {
+               helpmod_kick(hchan, (*hchanuser)->husr, reason);
+               continue;
+           }
+       hchanuser = &(*hchanuser)->next;
     }
 
     if (autoqueue_tmp > 0)
@@ -1980,7 +2029,7 @@ static void helpmod_cmd_activestaff (huser *sender, channel* returntype, char* o
         }
     }
 
-    arr = create_hstat_account_array(hchan, lvl);
+    arr = create_hstat_account_array(hchan, lvl, HSTAT_ACCOUNT_ARRAY_TOP10);
 
     helpmod_reply(sender, returntype, "%s %ss for channel %s", listtype?"Inactive":"Active", hlevel_name(lvl), hchannel_get_name(hchan));
     switch (listtype)
@@ -2024,14 +2073,14 @@ static void helpmod_cmd_top10 (huser *sender, channel* returntype, char* ostr, i
        else if (!ci_strcmp(argv[0], "all") || !ci_strcmp(argv[0], "a"))
             lvl = H_ANY;
     }
-    if (argc == 3)
+    if (argc == 2)
     {
         int tmp;
         if (sscanf(argv[1], "%d", &tmp) && (tmp >= 10) && (tmp <= 50))
             top_n = tmp;
     }
 
-    arr = create_hstat_account_array(hchan, lvl);
+    arr = create_hstat_account_array(hchan, lvl, HSTAT_ACCOUNT_ARRAY_TOP10);
 
     helpmod_reply(sender, returntype, "Top%d most active %ss of channel %s", top_n, hlevel_name(lvl), hchannel_get_name(hchan));
     for (i=0;i < arr.arrlen && i < top_n;i++)
@@ -2224,7 +2273,7 @@ static void helpmod_cmd_invite (huser *sender, channel *returntype, char* arg, i
         return;
     }
 
-    if (huser_get_level(sender) == H_PEON)
+    if (huser_get_level(sender) < H_STAFF)
     {
         hticket *htick;
         hchan = hchannel_get_by_name(argv[0]);
@@ -2269,16 +2318,20 @@ static void helpmod_cmd_invite (huser *sender, channel *returntype, char* arg, i
             helpmod_reply(sender, returntype, "Cannot invite: Unknown channel %s", argv[i]);
             continue;
         }
-        if (!(hchannel_authority(hchan, sender) || hticket_get(huser_get_auth(sender), hchan)))
-        {
-            helpmod_reply(sender, returntype, "Sorry, channel %s is oper only", hchannel_get_name(hchan));
-            continue;
-        }
-        if (huser_on_channel(sender, hchan) != NULL)
+       if (huser_on_channel(sender, hchan) != NULL)
         {
             helpmod_reply(sender, returntype, "Cannot invite: You are already on channel %s", hchannel_get_name(hchan));
             continue;
         }
+       if (!hchannel_authority(hchan, sender))
+       {
+           if (huser_get_level(sender) >= H_STAFF && (hchan->flags & H_REQUIRE_TICKET));
+           else
+           {
+               helpmod_reply(sender, returntype, "Sorry, channel %s is oper only", hchannel_get_name(hchan));
+               continue;
+           }
+        }
         helpmod_invite(hchan, sender);
         helpmod_reply(sender, returntype, "Invited you to channel %s", hchannel_get_name(hchan));
     }
@@ -2290,6 +2343,7 @@ static void helpmod_cmd_ticket (huser *sender, channel* returntype, char* ostr,
     hchannel *hchan;
     huser *husr;
     hticket *htick;
+    const char *message = NULL;
 
     if (argc < 1)
     {
@@ -2335,12 +2389,17 @@ static void helpmod_cmd_ticket (huser *sender, channel* returntype, char* ostr,
         helpmod_reply(sender, returntype, "Cannot issue a ticket: User %s does not require a ticket", argv[1]);
         return;
     }
-    if (argc >= 3)
+    if (argc > 3)
     {
-        int tmp;
+       int tmp;
         tmp = helpmod_read_strtime(argv[2]);
         if (tmp > HDEF_m && tmp < 2 * HDEF_M)
-            expiration = tmp;
+           expiration = tmp;
+    }
+    if (argc >= 4 && strlen(argv[3]) < 128)
+    {
+       if (argv[3][0] != '\0')
+            message = argv[3];
     }
 
     htick = hticket_get(huser_get_auth(husr), hchan);
@@ -2348,14 +2407,14 @@ static void helpmod_cmd_ticket (huser *sender, channel* returntype, char* ostr,
     if (htick != NULL)
         htick->time_expiration = time(NULL) + expiration;
     else
-        hticket_add(huser_get_auth(husr), time(NULL) + expiration, hchan);
+        hticket_add(huser_get_auth(husr), time(NULL) + expiration, hchan, message);
 
     helpmod_reply(sender, returntype, "Issued an invite ticket to user %s for channel %s expiring in %s", huser_get_nick(husr), hchannel_get_name(hchan), helpmod_strtime(expiration));
     helpmod_reply(husr, NULL, "You have been issued an invite ticket for channel %s. This ticket is valid for a period of %s. You can use my invite command to get to the channel now. Type /msg %s invite %s",hchannel_get_name(hchan), helpmod_strtime(HTICKET_EXPIRATION_TIME), helpmodnick->nick, hchannel_get_name(hchan));
     if (hchan->flags & H_TICKET_MESSAGE && hchan->ticket_message != NULL)
        helpmod_reply(husr, NULL, "Ticket information for %s: %s", hchannel_get_name(hchan), hchan->ticket_message->content);
-
 }
+
 static void helpmod_cmd_resolve (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
 {
     int i;
@@ -2461,8 +2520,6 @@ static void helpmod_cmd_showticket (huser *sender, channel* returntype, char* os
 
     DEFINE_HCHANNEL;
 
-    HCHANNEL_VERIFY_AUTHORITY(hchan, sender);
-
     if (argc > H_CMD_MAX_ARGS)
         argc = H_CMD_MAX_ARGS;
 
@@ -2489,8 +2546,11 @@ static void helpmod_cmd_showticket (huser *sender, channel* returntype, char* os
         {
             helpmod_reply(sender, returntype, "Cannot show the ticket: User %s does not have a valid ticket for channel %s", argv[i], hchannel_get_name(hchan));
             continue;
-        }
-        helpmod_reply(sender, returntype, "User %s has a ticket for channel %s expiring in %s", argv[i], hchannel_get_name(hchan), helpmod_strtime(htick->time_expiration - time(NULL)));
+       }
+       if (htick->message == NULL)
+           helpmod_reply(sender, returntype, "User %s has a ticket for channel %s expiring in %s. No message is attached.", argv[i], hchannel_get_name(hchan), helpmod_strtime(htick->time_expiration - time(NULL)));
+       else
+           helpmod_reply(sender, returntype, "User %s has a ticket for channel %s expiring in %s. With message: %s", argv[i], hchannel_get_name(hchan), helpmod_strtime(htick->time_expiration - time(NULL)), htick->message->content);
     }
 }
 
@@ -2597,9 +2657,9 @@ static void helpmod_cmd_checkchannel(huser *sender, channel* returntype, char* o
            if (IsAccount(nck))
                 authed_count++;
 
-            if (IsOper(nck) && strlen(nck->nick) > 1)
+            if (IsOper(nck) && strlen(nck->nick) > 1 && (IsSecret(chan) || IsPrivate(chan) || IsKey(chan) || IsInviteOnly(chan)))
             {
-                helpmod_reply(sender, returntype, "Cannot check channel: Permission denied. Channel %s has an oper on it", argv[0]);
+                helpmod_reply(sender, returntype, "Cannot check channel: Permission denied. Channel %s has an oper on it and one or more of +i/+k/+p/+s", argv[0]);
                 return;
             }
        }
@@ -2995,19 +3055,19 @@ static void helpmod_cmd_lcedit (huser *sender, channel* returntype, char* ostr,
        }
 
        helpmod_reply(sender, returntype, "Lamer control profile %s:", profile->name->content);
-       helpmod_reply(sender, returntype, "Maximum caps percentage:    %d", profile->caps_max_percentage);
-       helpmod_reply(sender, returntype, "Caps minimum count:         %d", profile->caps_min_count);
-       helpmod_reply(sender, returntype, "Repeat tolerance:           %d", profile->repeats_max_count);
-        helpmod_reply(sender, returntype, "Repeat minimum length:      %d", profile->repeats_min_length);
-        helpmod_reply(sender, returntype, "Symbol repeat tolerance:    %d", profile->symbol_repeat_max_count);
-       helpmod_reply(sender, returntype, "Character repeat tolerance: %d", profile->character_repeat_max_count);
-       helpmod_reply(sender, returntype, "Continous symbol tolerance: %d", profile->symbol_max_count);
-       helpmod_reply(sender, returntype, "Flood tolerance:            %d", profile->tolerance_flood);
-       helpmod_reply(sender, returntype, "Spam tolerance:             %d", profile->tolerance_spam);
-       helpmod_reply(sender, returntype, "Spam multiplier:            %f", profile->constant_spam);
-       helpmod_reply(sender, returntype, "Warning limit:              %d", profile->tolerance_warn);
-       helpmod_reply(sender, returntype, "Kick limit:                 %d", profile->tolerance_kick);
-       helpmod_reply(sender, returntype, "Ban limit:                  %d", profile->tolerance_remove);
+       helpmod_reply(sender, returntype, "Maximum caps percentage:     %d", profile->caps_max_percentage);
+       helpmod_reply(sender, returntype, "Caps minimum count:          %d", profile->caps_min_count);
+       helpmod_reply(sender, returntype, "Repeat tolerance:            %d", profile->repeats_max_count);
+        helpmod_reply(sender, returntype, "Repeat minimum length:       %d", profile->repeats_min_length);
+        helpmod_reply(sender, returntype, "Symbol repeat tolerance:     %d", profile->symbol_repeat_max_count);
+       helpmod_reply(sender, returntype, "Character repeat tolerance:  %d", profile->character_repeat_max_count);
+       helpmod_reply(sender, returntype, "Continuous symbol tolerance: %d", profile->symbol_max_count);
+       helpmod_reply(sender, returntype, "Flood tolerance:             %d", profile->tolerance_flood);
+       helpmod_reply(sender, returntype, "Spam tolerance:              %d", profile->tolerance_spam);
+       helpmod_reply(sender, returntype, "Spam multiplier:             %f", profile->constant_spam);
+       helpmod_reply(sender, returntype, "Warning limit:               %d", profile->tolerance_warn);
+       helpmod_reply(sender, returntype, "Kick limit:                  %d", profile->tolerance_kick);
+       helpmod_reply(sender, returntype, "Ban limit:                   %d", profile->tolerance_remove);
     }
     else if (!ci_strcmp(argv[0], "edit"))
     {
@@ -3115,36 +3175,74 @@ static void helpmod_cmd_text (huser *sender, channel* returntype, char* ostr, in
     {
        DIR *dir;
        struct dirent *dent;
-       char buffer[384];
-        int nwritten, bufpos = 0;
+       char buffer[384], **lines, *start;
+        int nwritten, bufpos = 0, nlines = 0,i;
 
        dir = opendir(HELPMOD_TEXT_DIR);
        assert(dir != NULL);
 
-       helpmod_reply(sender, returntype, "Following texts are available:");
-
+        /* First pass, count */
        for (dent = readdir(dir);dent != NULL;dent = readdir(dir))
        {
             /* Skip stuff like . and .. */
            if (!strncmp(dent->d_name, ".", 1))
                continue;
+            nlines++;
+       }
+
+       if (nlines == 0)
+       {
+           helpmod_reply(sender, returntype, "No texts are available.");
+            return;
+       }
+
+       helpmod_reply(sender, returntype, "Following texts are available:");
+
+       {
+           lines = (char **)malloc(sizeof(char*) * nlines);
+            *lines = (char *)malloc(sizeof(char) * (HED_FILENAME_LENGTH+1) * nlines);
+            /* We need the start to free this array */
+           start = *lines;
+           for(i=0;i < nlines;i++)
+               lines[i] = &lines[0][(HED_FILENAME_LENGTH+1) * i];
+       }
+        
+       /* Second pass, create array */
+        rewinddir(dir);
+       for (dent = readdir(dir), i = 0;dent != NULL && i < nlines;dent = readdir(dir))
+       {
+           /* Skip stuff like . and .. */
+           if (!strncmp(dent->d_name, ".", 1))
+               continue;
+           strncpy(lines[i], dent->d_name, 64);
+            i++;
+       }
+       /* Sort */
+       qsort(*lines, nlines, sizeof(char)*(HED_FILENAME_LENGTH+1), (int (*)(const void*, const void*))&strcmp);
 
+       for (i = 0;i < nlines;i++)
+       {
            if (bufpos)
            {
                buffer[bufpos] = ' ';
                bufpos++;
            }
-           sprintf(buffer + bufpos, "%s%n", dent->d_name, &nwritten);
+           sprintf(buffer + bufpos, "%s%n", lines[i], &nwritten);
            bufpos+=nwritten;
 
-           if (bufpos > 256)
+           if (bufpos > (384 - (HED_FILENAME_LENGTH+1)))
            {
                helpmod_reply(sender, returntype, buffer);
                bufpos = 0;
            }
        }
-        if (bufpos)
+
+       if (bufpos)
            helpmod_reply(sender, returntype, buffer);
+
+       free(start);
+        free(lines);
+
        return;
     }
     else if (!ci_strcmp(argv[0], "show"))
@@ -3171,10 +3269,10 @@ static void helpmod_cmd_text (huser *sender, channel* returntype, char* ostr, in
        {
            if (!fgets(buffer, 512, in))
                 break;
-           if (returntype != NULL && huser_get_level(sender) > H_PEON)
+           if (returntype != NULL && huser_get_level(sender) >= H_TRIAL)
                helpmod_message_channel(hchannel_get_by_channel(returntype), "%s", buffer);
            else
-                helpmod_reply(sender, returntype, "%s", buffer);
+               helpmod_reply(sender, returntype, "%s", buffer);
        }
        fclose (in);
         return;
@@ -3355,6 +3453,67 @@ static void helpmod_cmd_evilhack2 (huser *sender, channel* returntype, char* ost
     helpmod_reply(sender, returntype, "Evilhack2 done: Swapped %d and %d", first, second);
 }
 
+static void helpmod_cmd_channel (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
+{
+    hchannel *hchan;
+    hchannel_user *hchanuser;
+
+    DEFINE_HCHANNEL;
+
+    if (hchan == NULL)
+    {
+       helpmod_reply(sender, returntype, "Can not show channel: Channel not specified");
+        return;
+    }
+
+    HCHANNEL_VERIFY_AUTHORITY(hchan, sender);
+
+    helpmod_reply(sender, returntype, "Users for channel %s", hchannel_get_name(hchan));
+    helpmod_reply(sender, returntype, "Nick             Account          User level               Idle time");
+
+    for (hchanuser = hchan->channel_users;hchanuser;hchanuser=hchanuser->next)
+       helpmod_reply(sender, returntype, "%-16s %-16s %-24s %s",hchanuser->husr->real_user->nick,hchanuser->husr->account?hchanuser->husr->account->name->content:"-",hlevel_name(huser_get_level(hchanuser->husr)), helpmod_strtime(time(NULL)-huser_on_channel(hchanuser->husr, hchan)->last_activity));
+
+    helpmod_reply(sender, returntype, "Listed %d users for channel %s", hchannel_count_users(hchan, H_ANY), hchannel_get_name(hchan));
+}
+
+static void helpmod_cmd_weekstats (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
+{
+    hchannel *hchan;
+    hstat_accounts_array arr;
+    int i;
+    hlevel lvl = H_ANY;
+
+    DEFINE_HCHANNEL;
+
+    if (hchan == NULL)
+    {
+       helpmod_reply(sender, returntype, "Can not list weekly stats: Channel not specified");
+        return;
+    }
+
+    HCHANNEL_VERIFY_AUTHORITY(hchan, sender);
+
+    if (argc >= 1)
+    {
+        if (!ci_strcmp(argv[0], "opers") || !ci_strcmp(argv[0], "o"))
+            lvl = H_OPER;
+       else if (!ci_strcmp(argv[0], "staff") || !ci_strcmp(argv[0], "s"))
+           lvl = H_STAFF;
+       else if (!ci_strcmp(argv[0], "all") || !ci_strcmp(argv[0], "a"))
+            lvl = H_ANY;
+    }
+
+    arr = create_hstat_account_array(hchan, lvl, HSTAT_ACCOUNT_ARRAY_WEEKSTATS);
+
+    helpmod_reply(sender, returntype, "Weekly statistics for %ss on channel %s", hlevel_name(lvl), hchannel_get_name(hchan));
+
+    for (i=0;i < arr.arrlen && arr.array[i].time_spent > HDEF_m;i++)
+       helpmod_reply(sender, returntype, "%-20s %-20s %-20s",((haccount*)(arr.array[i].owner))->name->content, helpmod_strtime(arr.array[i].prime_time_spent), helpmod_strtime(arr.array[i].time_spent));
+
+    free(arr.array);
+}
+
 /* old H stuff */
 void helpmod_cmd_load (huser *sender, channel *returntype, char* arg, int argc, char *argv[])
 {
@@ -3526,10 +3685,12 @@ void hcommands_add(void)
 
     hcommand_add("improper", H_STAFF, helpmod_cmd_improper, "Sets the userlevel of the target to banned (lvl 0). Long term ban.");
     hcommand_add("peon", H_STAFF, helpmod_cmd_peon, "Sets the userlevel of the target to peon (lvl 1)");
-    hcommand_add("trial", H_OPER, helpmod_cmd_trial, "Sets the userlevel of the target to trial staff (lvl 2)");
-    hcommand_add("staff", H_OPER, helpmod_cmd_staff, "Sets the userlevel of the target to staff (lvl 3)");
-    hcommand_add("oper", H_OPER, helpmod_cmd_oper, "Sets the userlevel of the target to oper (lvl 4)");
-    hcommand_add("admin", H_ADMIN, helpmod_cmd_admin, "Sets the userlevel of the target to admin (lvl 5)");
+    hcommand_add("friend", H_STAFF, helpmod_cmd_friend, "Sets the userlevel of the target to friend (lvl 2)");
+    hcommand_add("trial", H_OPER, helpmod_cmd_trial, "Sets the userlevel of the target to trial staff (lvl 3)");
+    hcommand_add("staff", H_OPER, helpmod_cmd_staff, "Sets the userlevel of the target to staff (lvl 4)");
+
+    hcommand_add("oper", H_OPER, helpmod_cmd_oper, "Sets the userlevel of the target to oper (lvl 5)");
+    hcommand_add("admin", H_ADMIN, helpmod_cmd_admin, "Sets the userlevel of the target to admin (lvl 6)");
     hcommand_add("deluser", H_OPER, helpmod_cmd_deluser, "Removes an account from " HELPMOD_NICK);
     hcommand_add("listuser", H_STAFF, helpmod_cmd_listuser, "Lists user accounts of " HELPMOD_NICK);
 
@@ -3603,6 +3764,8 @@ void hcommands_add(void)
     hcommand_add("rating", H_TRIAL, helpmod_cmd_rating, "Simple rating for the current week");
     hcommand_add("writedb", H_OPER, helpmod_cmd_writedb, "Writes the " HELPMOD_NICK " database to disk");
 
+    hcommand_add("channel", H_TRIAL, helpmod_cmd_channel, "Gives a list of all channel users");
+    hcommand_add("weekstats", H_ADMIN, helpmod_cmd_weekstats, "Gives weekly stats for a channel");
     /*hcommand_add("megod", H_PEON, helpmod_cmd_megod, "Gives you userlevel 4, if you see this in the final version, please kill strutsi");*/
     /*hcommand_add("test", H_PEON, helpmod_cmd_test, "Gives you userlevel 4, if you see this in the final version, please kill strutsi");*/
 }
@@ -3611,7 +3774,7 @@ void helpmod_command(huser *sender, channel* returntype, char *args)
 {
     int argc = 0, useless_var;
     char args_copy[512];
-    char *parsed_args[H_CMD_MAX_ARGS + 3], *ptr = args_copy;
+    char *parsed_args[H_CMD_MAX_ARGS + 4], *ptr = args_copy;
 
     /* only accept commands from valid sources */
     if (huser_get_level(sender) > H_ADMIN)
@@ -3628,9 +3791,11 @@ void helpmod_command(huser *sender, channel* returntype, char *args)
     if (*args == '-' || *args == '?')
         args++;
 
-    strcpy(args_copy, args);
+    strncpy(args_copy, args, (sizeof(args_copy) - 1));
+    args_copy[sizeof(args_copy) - 1] = '\0';
+
     /* FIX stringituki */
-    while (argc < 10)
+    while (argc < (H_CMD_MAX_ARGS + 4))
     {
         while (isspace(*ptr) && *ptr)
             ptr++;
@@ -3687,6 +3852,7 @@ void helpmod_command(huser *sender, channel* returntype, char *args)
        }
         else
         {
+            controlwall(NO_DEVELOPER, NL_ALL_COMMANDS, "(G) From: %s!%s@%s%s%s: %s", sender->real_user->nick, sender->real_user->ident, sender->real_user->host->name->content, IsAccount(sender->real_user)?"/":"", IsAccount(sender->real_user)?sender->real_user->authname:"", args);
             SKIP_WORD;
             hcom->function(sender, returntype, ostr, argc, argv);
         }