]> 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 1856fd8beb9e152aac759753f90f839154fef930..56b2574b3667357719ca26a52670f06971ccba28 100644 (file)
@@ -2,10 +2,8 @@
 #include <ctype.h>
 #include <stdio.h>
 #include <assert.h>
-
-#include "../nick/nick.h"
-#include "../channel/channel.h"
-#include "../lib/irc_string.h"
+#include <sys/types.h>
+#include <dirent.h>
 
 #include "hcommands.h"
 #include "hcommand.h"
@@ -23,6 +21,7 @@
 #include "hchanban.h"
 
 #include "hticket.h"
+#include "hconf.h"
 
 /* following are macros for use ONLY IN HERE
  they may not look pretty, but work surprisingly well */
@@ -180,9 +179,12 @@ static void helpmod_cmd_whois (huser *sender, channel* returntype, char* ostr, i
     {
         husr = huser_get(getnickbynick(argv[i]));
         if (husr == NULL)
-        {
-            helpmod_reply(sender, returntype, "Cannot get user information: User %s not found", argv[i]);
-            continue;
+       {
+           if (getnickbynick(argv[i]) == NULL)
+                helpmod_reply(sender, returntype, "Cannot get user information: User %s does not exist in the network", argv[i]);
+           else
+               helpmod_reply(sender, returntype, "Cannot get user information: User %s exists but is not known to me", argv[i]);
+           continue;
         }
         helpmod_reply(sender, returntype, "User %s has userlevel %s", huser_get_nick(husr), hlevel_name(huser_get_level(husr)));
        if (husr->account == NULL)
@@ -348,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));
@@ -368,8 +382,9 @@ static void helpmod_cmd_change_userlevel(huser *sender, hlevel target_level, cha
 
             target_huser->account->level = target_level;
 
-            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)
+           helpmod_reply(sender, returntype, "Userlevel changed: User '%s' now has userlevel %s", argv[i], hlevel_name(target_level));
+
+            if (target_level != H_LAMER)
                helpmod_reply(target_huser, NULL, "Your userlevel has been changed, your current userlevel is %s", hlevel_name(target_level));
         }
     }
@@ -378,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); }
@@ -489,7 +505,7 @@ static void helpmod_cmd_censor (huser *sender, channel* returntype, char* ostr,
         return;
     }
 
-    if (argc < 2) /* view */
+    if (argc < 2 || !ci_strcmp(argv[0], "list")) /* view */
     {
         if (hchan->censor == NULL)
             helpmod_reply(sender, returntype, "Nothing is censored on channel %s", hchan->real_channel->index->name->content);
@@ -497,7 +513,7 @@ static void helpmod_cmd_censor (huser *sender, channel* returntype, char* ostr,
         {
             helpmod_reply(sender, returntype, "Censored patterns for channel %s (%s):", hchan->real_channel->index->name->content, (hchan->flags & H_CENSOR)?"active":"inactive");
             for (hcens = hchan->censor;hcens;hcens = hcens->next)
-                helpmod_reply(sender, returntype, "#%d %-8s %s%s%s", i++, hcensor_get_typename(hcens->type), hcens->pattern->content, hcens->reason?" :: ":"", hcens->reason?hcens->reason->content:"");
+                helpmod_reply(sender, returntype, "#%-4d %-8s %s%s%s", i++, hcensor_get_typename(hcens->type), hcens->pattern->content, hcens->reason?" :: ":"", hcens->reason?hcens->reason->content:"");
         }
     }
     else
@@ -528,6 +544,11 @@ static void helpmod_cmd_censor (huser *sender, channel* returntype, char* ostr,
                     type = HCENSOR_KICK;
                     SKIP_WORD;
                }
+               else if (!ci_strcmp(argv[0], "chanban"))
+               {
+                    type = HCENSOR_CHANBAN;
+                    SKIP_WORD;
+               }
                else if (!ci_strcmp(argv[0], "ban"))
                {
                     type = HCENSOR_BAN;
@@ -536,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;
 
@@ -768,7 +796,7 @@ static void helpmod_cmd_aliases (huser *sender, channel* returntype, char* ostr,
 
 static void helpmod_cmd_showcommands (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
 {
-    int level = H_PEON;
+    int level = H_PEON, previous_level = H_PEON;
     hcommand *tmp;
 
     if (!(argc && (sscanf(argv[0], "%d", &level)) && (level >= 0) && (level <= huser_get_level(sender))))
@@ -779,7 +807,14 @@ static void helpmod_cmd_showcommands (huser *sender, channel* returntype, char*
     hcommand_list(H_NONE);
 
     while ((tmp = hcommand_list(level)) != NULL)
-        helpmod_reply(sender, returntype, "%-16s %s", tmp->name->content, tmp->help->content);
+    {
+       if (tmp->level > previous_level)
+       {
+           helpmod_reply(sender, returntype, "--- Additional commands for userlevel %s ---", hlevel_name(tmp->level));
+           previous_level = tmp->level;
+       }
+       helpmod_reply(sender, returntype, "%-16s %s", tmp->name->content, tmp->help->content);
+    }
 
     return;
 }
@@ -858,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);
 
@@ -887,8 +922,9 @@ static void helpmod_cmd_term_find_general (huser *sender, channel* returntype, i
             char buffer[256] = "";
             for (i=0;i<ntargets;i++)
             {
-                strcat(buffer, " ");
-                strcat(buffer, huser_get_nick(targets[i]));
+                if (i != 0)
+                   strcat(buffer, " ");
+               strcat(buffer, huser_get_nick(targets[i]));
             }
 
             helpmod_message_channel_long(hchannel_get_by_channel(returntype), "%s: (%s) %s", buffer, htrm->name->content, htrm->description->content);
@@ -958,7 +994,7 @@ static void helpmod_cmd_klingon (huser *sender, channel* returntype, char* ostr,
     }
 }
 
-static void helpmod_cmd_term (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
+void helpmod_cmd_term (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
 {
     hterm *htrm;
     hterm **source;
@@ -1002,7 +1038,7 @@ static void helpmod_cmd_term (huser *sender, channel* returntype, char* ostr, in
             }
             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++;
             }
         }
@@ -1083,7 +1119,7 @@ static void helpmod_cmd_term (huser *sender, channel* returntype, char* ostr, in
             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);
@@ -1217,19 +1253,13 @@ static void helpmod_cmd_dnmo (huser *sender, channel* returntype, char* ostr, in
 
 static void helpmod_cmd_ban (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
 {
-    if (argc == 0)
-    {
-        helpmod_reply(sender, returntype, "Cannot global handle bans: Operation not defined");
-        return;
-    }
-
-    else if (!ci_strcmp(argv[0], "list"))
+    if (argc == 0 || !ci_strcmp(argv[0], "list"))
     {
         hban *ptr = hbans;
         char *pattern;
         int count = 0;
 
-        if (argc == 1)
+        if (argc <= 1)
             pattern = "*";
         else
             pattern = argv[1];
@@ -1239,13 +1269,12 @@ static void helpmod_cmd_ban (huser *sender, channel* returntype, char* ostr, int
         for (;ptr;ptr = ptr->next)
             if (strregexp(bantostring(ptr->real_ban), pattern))
             {
-                helpmod_reply(sender, returntype, "%-64s %-15s %s", bantostring(ptr->real_ban), helpmod_strtime(ptr->expiration - time(NULL)), ptr->reason?ptr->reason->content:"");
+                helpmod_reply(sender, returntype, "%-64s %-20s %s", bantostring(ptr->real_ban), helpmod_strtime(ptr->expiration - time(NULL)), ptr->reason?ptr->reason->content:"");
                 count++;
             }
 
         helpmod_reply(sender, returntype, "%d Global bans match pattern %s", count, pattern);
     }
-
     else if (!ci_strcmp(argv[0], "add"))
     {
         int duration = 4 * HDEF_h;
@@ -1319,20 +1348,20 @@ static void helpmod_cmd_chanban (huser *sender, channel* returntype, char* ostr,
     }
 
     HCHANNEL_VERIFY_AUTHORITY(hchan, sender);
-
+/*
     if (argc == 0)
     {
         helpmod_reply(sender, returntype, "Cannot handle channel bans: Operation not defined");
         return;
     }
-
-    if (!ci_strcmp(argv[0], "list"))
+*/
+    if (argc == 0 || !ci_strcmp(argv[0], "list"))
     {
         char *pattern, *cban;
         chanban *ptr = hchan->real_channel->bans;
         int count = 0;
 
-        if (argc ==  1)
+        if (argc <=  1)
             pattern = "*";
         else
             pattern = argv[1];
@@ -1342,8 +1371,8 @@ static void helpmod_cmd_chanban (huser *sender, channel* returntype, char* ostr,
             if (strregexp((cban = bantostring(ptr)), pattern))
             {
                 count++;
-                if (hchanban_get(hchan,cban))
-                    helpmod_reply(sender, returntype, "%s Expires in %s", bantostring(ptr), helpmod_strtime(hchanban_get(hchan, cban)->expiration - time(NULL)));
+                if (hchanban_get(hchan,cban) != NULL)
+                   helpmod_reply(sender, returntype, "%s Expires in %s", bantostring(ptr), helpmod_strtime(hchanban_get(hchan, cban)->expiration - time(NULL)));
                 else
                     helpmod_reply(sender, returntype, "%s", bantostring(ptr));
             }
@@ -1555,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;
        }
 
@@ -1576,10 +1621,11 @@ static void helpmod_cmd_out (huser *sender, channel* returntype, char* ostr, int
     {
        const char *banmask = hban_ban_string(targets[i]->real_user, HBAN_HOST);
 
-       hban_add(banmask, reason, time(NULL) + HCMD_OUT_DEFAULT, 0);
+       hban_add(banmask, reason, time(NULL) + HCMD_OUT_DEFAULT, HLAZY);
 
        helpmod_reply(sender, returntype, "User %s is now gone", huser_get_nick(targets[i]));
     }
+    hcommit_modes();
 }
 
 static void helpmod_cmd_everyoneout (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
@@ -1588,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;
 
@@ -1600,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);
@@ -1615,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)
@@ -1882,7 +1950,6 @@ static void helpmod_cmd_chanstats (huser *sender, channel* returntype, char* ost
             }
         }
 
-
     channel_stats = hchan->stats;
 
     if (!days && !weeks)
@@ -1940,7 +2007,12 @@ static void helpmod_cmd_activestaff (huser *sender, channel* returntype, char* o
         {
             lvl = H_STAFF;
             SKIP_WORD;
-        }
+       }
+       else if (!ci_strcmp(argv[0], "staff") || !ci_strcmp(argv[0], "s"))
+       {
+            lvl = H_ANY;
+            SKIP_WORD;
+       }
     }
 
     if (argc == 1)
@@ -1957,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)
@@ -2001,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++)
@@ -2201,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]);
@@ -2240,22 +2312,26 @@ static void helpmod_cmd_invite (huser *sender, channel *returntype, char* arg, i
 
     for (i = 0;i < argc; i++)
     {
-        hchan = hchannel_get_by_name(argv[0]);
+        hchan = hchannel_get_by_name(argv[i]);
         if (hchan == NULL)
         {
             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));
     }
@@ -2267,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)
     {
@@ -2307,12 +2384,22 @@ static void helpmod_cmd_ticket (huser *sender, channel* returntype, char* ostr,
         helpmod_reply(sender, returntype, "Cannot issue a ticket: User %s is considered improper and not worthy of a ticket", argv[1]);
         return;
     }
-    if (argc >= 3)
+    if (huser_get_level(husr) > H_PEON)
     {
-        int tmp;
+        helpmod_reply(sender, returntype, "Cannot issue a ticket: User %s does not require a ticket", argv[1]);
+        return;
+    }
+    if (argc > 3)
+    {
+       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);
@@ -2320,10 +2407,12 @@ 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[])
@@ -2431,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;
 
@@ -2459,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);
     }
 }
 
@@ -2477,6 +2567,8 @@ static void helpmod_cmd_termstats(huser *sender, channel* returntype, char* ostr
 
     DEFINE_HCHANNEL;
 
+    HCHANNEL_VERIFY_AUTHORITY(hchan, sender);
+
     if (hchan == NULL)
         origin = hterms;
     else
@@ -2565,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;
             }
        }
@@ -2829,6 +2921,475 @@ static void helpmod_cmd_version (huser *sender, channel* returntype, char* ostr,
     helpmod_reply(sender, returntype, "HelpMod version " HELPMOD_VERSION " by strutsi (strutsi@quakenet.org)");
 }
 
+static void helpmod_cmd_ticketmsg (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
+{
+    hchannel *hchan;
+
+    DEFINE_HCHANNEL;
+
+    HCHANNEL_VERIFY_AUTHORITY(hchan, sender);
+
+    if (hchan == NULL)
+    {
+       helpmod_reply(sender, returntype, "Can not view or set ticket message: No channel is specified.");
+       return;
+    }
+
+    if (argc == 0)
+    { /* view */
+       if (hchan->ticket_message == NULL)
+           helpmod_reply(sender, returntype, "No ticket message is set for channel %s", hchannel_get_name(hchan));
+       else
+           helpmod_reply(sender, returntype, "Ticket message for channel %s is: %s", hchannel_get_name(hchan), hchan->ticket_message->content);
+       return;
+    }
+
+    /* set */
+    if (hchan->ticket_message != NULL)
+       freesstring(hchan->ticket_message);
+
+    hchan->ticket_message = getsstring(ostr, strlen(ostr));
+    helpmod_reply(sender, returntype, "Ticket message for channel %s set to: %s", hchannel_get_name(hchan), hchan->ticket_message->content);
+}
+
+static void helpmod_cmd_lcedit (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
+{
+    hlc_profile *profile;
+
+    if (argc == 0)
+    {
+       helpmod_reply(sender, returntype, "Can not handle lamer control profiles: Operation not defined");
+        return;
+    }
+
+    if (!ci_strcmp(argv[0], "list"))
+    {
+       if (hlc_profiles == NULL)
+       {
+           helpmod_reply(sender, returntype, "Can not list lamer control profiles: No profiles");
+            return;
+       }
+       helpmod_reply(sender, returntype, "Following lamer control profiles are currently available:");
+       for (profile = hlc_profiles;profile != NULL;profile = profile->next)
+           helpmod_reply(sender, returntype, "%s", profile->name->content);
+    }
+    else if (!ci_strcmp(argv[0], "add"))
+    {
+       if (argc < 2)
+       {
+           helpmod_reply(sender, returntype, "Can not add a lamer control profile: Profile name not defined");
+            return;
+       }
+
+       profile = hlc_get(argv[1]);
+
+       if (profile != NULL)
+       {
+           helpmod_reply(sender, returntype, "Can not add a lamer control profile: Profile named %s already exists", argv[1]);
+           return;
+       }
+       profile = hlc_add(argv[1]);
+
+       { /* set the default values */
+           profile->caps_max_percentage = 40;
+           profile->caps_min_count = 20;
+
+           profile->repeats_max_count = 3;
+           profile->repeats_min_length = 7;
+
+           profile->symbol_repeat_max_count = 6;
+           profile->character_repeat_max_count = 7;
+           profile->symbol_max_count = 9;
+
+           profile->tolerance_flood = 5;
+
+           profile->tolerance_spam = 0.008;
+           profile->constant_spam = 10;
+
+           profile->tolerance_warn = 1;
+           profile->tolerance_kick = 3;
+           profile->tolerance_remove = 5;
+       }
+
+       helpmod_reply(sender, returntype, "Lamer control profile %s added", argv[1]);
+    }
+    else if (!ci_strcmp(argv[0], "del"))
+    {
+        hchannel *hchan;
+       if (argc < 2)
+       {
+           helpmod_reply(sender, returntype, "Can not delete a lamer control profile: Profile name not defined");
+            return;
+       }
+
+       profile = hlc_get(argv[1]);
+
+       if (profile == NULL)
+       {
+           helpmod_reply(sender, returntype, "Can not delete a lamer control profile: Profile named %s does not exist", argv[1]);
+           return;
+       }
+       for (hchan = hchannels;hchan != NULL;hchan = hchan->next)
+           if (hchan->lc_profile == profile)
+           {
+               helpmod_reply(sender, returntype, "Can not delete a lamer control profile: Profile %s is in use", argv[1]);
+               return;
+           }
+       hlc_del(profile);
+       helpmod_reply(sender, returntype, "Lamer control profile %s deleted", argv[1]);
+    }
+    else if (!ci_strcmp(argv[0], "view"))
+    {
+       if (argc < 2)
+       {
+           helpmod_reply(sender, returntype, "Can not view a lamer control profile: Profile name not defined");
+           return;
+       }
+
+       profile = hlc_get(argv[1]);
+
+       if (profile == NULL)
+       {
+           helpmod_reply(sender, returntype, "Can not view a lamer control profile: Profile named %s not found", argv[1]);
+           return;
+       }
+
+       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, "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"))
+    {
+       int int_val = -1;
+       double dbl_val = -1;
+
+       if (argc != 4)
+       {
+           helpmod_reply(sender, returntype, "Can not edit a lamer control profile: Syntax error");
+            return;
+       }
+
+       profile = hlc_get(argv[1]);
+
+       if (profile == NULL)
+       {
+           helpmod_reply(sender, returntype, "Can not edit a lamer control profile: Profile %s not found", argv[1]);
+           return;
+       }
+
+       sscanf(argv[3], "%d", &int_val);
+        sscanf(argv[3], "%lf", &dbl_val);
+
+       if (dbl_val < 0)
+       {   /* All int values are also valid double values */
+           helpmod_reply(sender, returntype, "Can not edit a lamer control profile: Invalid argument");
+            return;
+       }
+
+       if (!ci_strcmp(argv[2], "caps_percentage"))
+           profile->caps_max_percentage = int_val;
+        else if (!ci_strcmp(argv[2], "caps_count"))
+           profile->caps_min_count = int_val;
+        else if (!ci_strcmp(argv[2], "repeat_tolerance"))
+           profile->repeats_max_count = int_val;
+        else if (!ci_strcmp(argv[2], "repeat_length"))
+           profile->repeats_min_length = int_val;
+        else if (!ci_strcmp(argv[2], "symbol_repeat"))
+           profile->symbol_repeat_max_count = int_val;
+        else if (!ci_strcmp(argv[2], "character_repeat"))
+           profile->character_repeat_max_count = int_val;
+       else if (!ci_strcmp(argv[2], "continuous_symbol"))
+           profile->symbol_max_count = int_val;
+       else if (!ci_strcmp(argv[2], "flood_tolerance"))
+           profile->tolerance_flood = int_val;
+       else if (!ci_strcmp(argv[2], "spam_tolerance"))
+           profile->tolerance_spam = int_val;
+       else if (!ci_strcmp(argv[2], "spam_multiplier"))
+           profile->constant_spam = dbl_val;
+       else if (!ci_strcmp(argv[2], "warn_limit"))
+           profile->tolerance_warn = int_val;
+       else if (!ci_strcmp(argv[2], "kick_limit"))
+           profile->tolerance_kick = int_val;
+       else if (!ci_strcmp(argv[2], "ban_limit"))
+           profile->tolerance_remove = int_val;
+       else
+       {
+           helpmod_reply(sender, returntype, "Can not edit a lamer control profile: No component named %s", argv[2]);
+           return;
+       }
+       helpmod_reply(sender, returntype, "Lamer control profile component value changed succesfully.");
+    }
+}
+
+static void helpmod_cmd_ged (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
+{
+    helpmod_editor *editor;
+
+    if (sender->editor == NULL)
+    { /* Start a new editor */
+       if (argc == 0)
+       {
+           helpmod_reply(sender, returntype, "Can not use ged: Filename not specified");
+           return;
+       }
+       editor = hed_open(sender, argv[0]);
+       if (editor == NULL)
+       {
+           helpmod_reply(sender, returntype, "Can not use ged: Invalid filename %s", argv[0]);
+            return;
+       }
+       if (editor->user != sender)
+       {
+           helpmod_reply(sender, returntype, "Can not use ged: File %s is currently being edited by %s", editor->filename, huser_get_nick(editor->user));
+            return;
+       }
+       editor->user = sender;
+       sender->editor = editor;
+
+       helpmod_reply(sender, returntype, "Ged: %d", hed_byte_count(editor));
+    }
+    else
+    {
+       hed_command(sender, returntype, ostr, argc, argv);
+    }
+}
+
+static void helpmod_cmd_text (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
+{
+    hchannel *hchan;
+    DEFINE_HCHANNEL;
+    FILE *in;
+
+    if (argc == 0 || !ci_strcmp(argv[0], "list"))
+    {
+       DIR *dir;
+       struct dirent *dent;
+       char buffer[384], **lines, *start;
+        int nwritten, bufpos = 0, nlines = 0,i;
+
+       dir = opendir(HELPMOD_TEXT_DIR);
+       assert(dir != NULL);
+
+        /* 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", lines[i], &nwritten);
+           bufpos+=nwritten;
+
+           if (bufpos > (384 - (HED_FILENAME_LENGTH+1)))
+           {
+               helpmod_reply(sender, returntype, buffer);
+               bufpos = 0;
+           }
+       }
+
+       if (bufpos)
+           helpmod_reply(sender, returntype, buffer);
+
+       free(start);
+        free(lines);
+
+       return;
+    }
+    else if (!ci_strcmp(argv[0], "show"))
+    {
+        char fname_buffer[128], buffer[512];
+       if (argc < 2)
+       {
+           helpmod_reply(sender, returntype, "Can not show text: Text not specified");
+            return;
+       }
+       if (!hed_is_valid_filename(argv[1]))
+       {
+           helpmod_reply(sender, returntype, "Can not show text: Invalid filename");
+            return;
+       }
+       sprintf(fname_buffer, HELPMOD_TEXT_DIR"/%s" ,argv[1]);
+       in = fopen(fname_buffer, "rwt");
+       if (in == NULL)
+       {
+           helpmod_reply(sender, returntype, "Can not show text: Text %s not found", argv[1]);
+            return;
+       }
+       while (!feof(in))
+       {
+           if (!fgets(buffer, 512, in))
+                break;
+           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);
+       }
+       fclose (in);
+        return;
+    }
+
+    if (huser_get_level(sender) < H_STAFF)
+    {
+       helpmod_reply(sender, returntype, "Can not handle text: Insufficient user level");
+        return;
+    }
+
+    if (!ci_strcmp(argv[0], "add"))
+    {
+       char fname_buffer[128];
+       if (argc < 2)
+       {
+           helpmod_reply(sender, returntype, "Can not add text: Text not specified");
+            return;
+       }
+       if (!hed_is_valid_filename(argv[1]))
+       {
+           helpmod_reply(sender, returntype, "Can not add text: Invalid filename");
+           return;
+       }
+       sprintf(fname_buffer, HELPMOD_TEXT_DIR"/%s" ,argv[1]);
+       if ((in = fopen(fname_buffer, "rt")) != NULL)
+       {
+           helpmod_reply(sender, returntype, "Can not add text: Text %s already exists", argv[1]);
+            return;
+       }
+       else
+       {
+           if ((in = fopen(fname_buffer, "wt")) == NULL)
+           {
+               helpmod_reply(sender, returntype, "Can not add text: Unexpected error, please contact strutsi");
+                return;
+           }
+           fclose(in);
+       }
+       helpmod_reply(sender, returntype, "Text %s added succesfully", argv[1]);
+    }
+    else if (!ci_strcmp(argv[0], "del"))
+    {
+       char fname_buffer[128];
+       if (argc < 2)
+       {
+           helpmod_reply(sender, returntype, "Can not delete text: Text not specified");
+            return;
+       }
+       if (!hed_is_valid_filename(argv[1]))
+       {
+           helpmod_reply(sender, returntype, "Can not delete text: Invalid filename");
+           return;
+       }
+       sprintf(fname_buffer, HELPMOD_TEXT_DIR"/%s" ,argv[1]);
+
+       if (!remove(fname_buffer))
+           helpmod_reply(sender, returntype, "Text %s removed", argv[1]);
+       else
+           helpmod_reply(sender, returntype, "Can not delete text: Text %s does not exist or can not be deleted", argv[1]);
+    }
+    else
+    {
+       helpmod_reply(sender, returntype, "Can not handle text: Unknown operation %s", argv[0]);
+        return;
+    }
+}
+
+static void helpmod_cmd_rating (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
+{
+    hchannel *hchan;
+    hstat_account_entry sum = {0,0,0,0};
+    hstat_account *ptr;
+    int i;
+
+    DEFINE_HCHANNEL;
+
+    HCHANNEL_VERIFY_AUTHORITY(hchan, sender);
+
+    if (hchan == NULL)
+    {
+       helpmod_reply(sender, returntype, "Can not show rating: Unknown channel");
+        return;
+    }
+    if (sender->account == NULL)
+    {
+       helpmod_reply(sender, returntype, "Can not show rating: You do not have an account");
+        return;
+    }
+    for (ptr = sender->account->stats;ptr != NULL;ptr = ptr->next)
+       if (ptr->hchan == hchan)
+       {
+           if (hstat_day() == 0)
+           { /* Sunday screws the indexing */
+               for (i = 0;i < 7;i++)
+                   HSTAT_ACCOUNT_SUM(sum, sum, ptr->week[i]);
+           }
+           else
+           { /* Normal case */
+               for (i = 1;i <= hstat_day();i++)
+                   HSTAT_ACCOUNT_SUM(sum, sum, ptr->week[i]);
+           }
+
+           helpmod_reply(sender, returntype, "Your rating for channel %s for this week is: %s", hchannel_get_name(hchan), helpmod_strtime(sum.time_spent));
+           return;
+       }
+    helpmod_reply(sender, returntype, "Can not show rating: You do not have any statistics for channel %s", hchannel_get_name(hchan));
+}
+
+static void helpmod_cmd_writedb (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
+{
+    rename(HELPMOD_DEFAULT_DB, HELPMOD_DEFAULT_DB".old");
+    helpmod_config_write(HELPMOD_DEFAULT_DB);
+
+    helpmod_reply(sender, returntype, "Database written");
+}
+
 static void helpmod_cmd_evilhack1 (huser *sender, channel* returntype, char* ostr, int argc, char *argv[])
 {
     int tmp;
@@ -2892,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[])
 {
@@ -2976,9 +3598,13 @@ void helpmod_cmd_command(huser* sender, channel* returntype, char* arg, int argc
     while (*(ptr++))
         *ptr = tolower(*ptr);
 
-    /* ? is handled like this because windows is shit */
+    /* ?,?+.?- is handled like this because windows is shit */
     if (!ci_strcmp(argv[0], "?"))
        sprintf(buffer, "./helpmod2/commands/questionmark");
+    else if (!ci_strcmp(argv[0], "?+"))
+       sprintf(buffer, "./helpmod2/commands/questionmarkplus");
+    else if (!ci_strcmp(argv[0], "?-"))
+       sprintf(buffer, "./helpmod2/commands/questionmarkminus");
     else
        sprintf(buffer, "./helpmod2/commands/%s", argv[0]);
 
@@ -3059,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);
 
@@ -3105,8 +3733,8 @@ void hcommands_add(void)
     hcommand_add("command", H_LAMER, helpmod_cmd_command, "Gives detailed information on a command");
     hcommand_add("addchan", H_ADMIN, helpmod_cmd_addchan, "Joins " HELPMOD_NICK " to a new channel");
     hcommand_add("delchan", H_ADMIN, helpmod_cmd_delchan, "Removes " HELPMOD_NICK " permanently from a channel");
-    hcommand_add("seen", H_STAFF, helpmod_cmd_seen, "Tells when a specific user/account has had activity");
 
+    hcommand_add("seen", H_STAFF, helpmod_cmd_seen, "Tells when a specific user/account has had activity");
     hcommand_add("op", H_STAFF, helpmod_cmd_op, "Sets mode +o on channels");
     hcommand_add("deop", H_STAFF, helpmod_cmd_deop, "Sets mode -o on channels");
     hcommand_add("voice", H_TRIAL, helpmod_cmd_voice, "Sets mode +v on channels");
@@ -3120,17 +3748,24 @@ void hcommands_add(void)
 
     hcommand_add("termstats", H_OPER, helpmod_cmd_termstats, "Lists usage statistics for terms");
     hcommand_add("checkchannel", H_STAFF, helpmod_cmd_checkchannel, "Shows channel information for any channel");
-    hcommand_add("statsdump", H_ADMIN, helpmod_cmd_statsdump, "Statistics dump command");
-    hcommand_add("statsrepair", H_ADMIN, helpmod_cmd_statsrepair, "Statistics repair command");
-    hcommand_add("statsreset", H_ADMIN, helpmod_cmd_statsreset, "Statistics reset command");
-
     hcommand_add("message", H_TRIAL, helpmod_cmd_message, "Sends a message to a channel");
     hcommand_add("version", H_PEON, helpmod_cmd_version, "G version information");
+    hcommand_add("ticketmsg", H_STAFF, helpmod_cmd_ticketmsg, "Handle the ticket message for a channel");
 
+    hcommand_add("lcedit", H_ADMIN, helpmod_cmd_lcedit, "Lamer control profile manager");
+    hcommand_add("ged", H_STAFF, helpmod_cmd_ged, "Ged IRC text editor");
+    hcommand_add("text", H_PEON, helpmod_cmd_text, "Lists or shows text files");
     hcommand_add("evilhack1", H_ADMIN, helpmod_cmd_evilhack1, "An evil hack, don't use");
     hcommand_add("evilhack2", H_ADMIN, helpmod_cmd_evilhack2, "Another evil hack, don't use");
 
+    hcommand_add("statsdump", H_ADMIN, helpmod_cmd_statsdump, "Statistics dump command");
+    hcommand_add("statsrepair", H_ADMIN, helpmod_cmd_statsrepair, "Statistics repair command");
+    hcommand_add("statsreset", H_ADMIN, helpmod_cmd_statsreset, "Statistics reset command");
+    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");*/
 }
@@ -3139,10 +3774,10 @@ 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_PEON || huser_get_level(sender) > H_ADMIN)
+    if (huser_get_level(sender) > H_ADMIN)
         return;
 
     if (returntype && !strncmp(args, helpmodnick->nick, strlen(helpmodnick->nick)))
@@ -3156,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++;
@@ -3209,11 +3846,13 @@ void helpmod_command(huser *sender, channel* returntype, char *args)
 
        if (hcom == NULL)
        {
-           if ((sender->account == NULL && returntype == NULL) || (sender->account != NULL && !(sender->account->flags & H_NO_CMD_ERROR)))
+           if ((returntype == NULL) ||
+               (sender->account != NULL && !(sender->account->flags & H_NO_CMD_ERROR)))
                helpmod_reply(sender, returntype, "Unknown command '%s', please see showcommands for a list of all commands available to you", parsed_args[0]);
        }
         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);
         }