]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/command_parse.cpp
Added example conf
[user/henk/code/inspircd.git] / src / command_parse.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 using namespace std;
18
19 #include "inspircd_config.h"
20 #include "inspircd.h"
21 #include "inspircd_io.h"
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <sys/errno.h>
25 #include <sys/ioctl.h>
26 #include <sys/utsname.h>
27 #include <time.h>
28 #include <string>
29 #ifdef GCC3
30 #include <ext/hash_map>
31 #else
32 #include <hash_map>
33 #endif
34 #include <map>
35 #include <sstream>
36 #include <vector>
37 #include <deque>
38 #include <sched.h>
39 #ifdef THREADED_DNS
40 #include <pthread.h>
41 #endif
42 #include "users.h"
43 #include "globals.h"
44 #include "modules.h"
45 #include "dynamic.h"
46 #include "wildcard.h"
47 #include "message.h"
48 #include "mode.h"
49 #include "commands.h"
50 #include "xline.h"
51 #include "inspstring.h"
52 #include "dnsqueue.h"
53 #include "helperfuncs.h"
54 #include "hashcomp.h"
55 #include "socketengine.h"
56 #include "userprocess.h"
57 #include "socket.h"
58 #include "dns.h"
59 #include "typedefs.h"
60 #include "command_parse.h"
61 #include "ctables.h"
62
63 #ifdef GCC3
64 #define nspace __gnu_cxx
65 #else
66 #define nspace std
67 #endif
68
69
70 extern InspIRCd* ServerInstance;
71
72 extern std::vector<Module*> modules;
73 extern std::vector<ircd_module*> factory;
74 extern std::vector<InspSocket*> module_sockets;
75 extern std::vector<userrec*> local_users;
76
77 extern int MODCOUNT;
78 extern InspSocket* socket_ref[MAX_DESCRIPTORS];
79 extern time_t TIME;
80
81 // This table references users by file descriptor.
82 // its an array to make it VERY fast, as all lookups are referenced
83 // by an integer, meaning there is no need for a scan/search operation.
84 extern userrec* fd_ref_table[MAX_DESCRIPTORS];
85
86 extern Server* MyServer;
87 extern ServerConfig *Config;
88
89 extern user_hash clientlist;
90 extern chan_hash chanlist;
91
92 /* This function pokes and hacks at a parameter list like the following:
93  *
94  * PART #winbot,#darkgalaxy :m00!
95  *
96  * to turn it into a series of individual calls like this:
97  *
98  * PART #winbot :m00!
99  * PART #darkgalaxy :m00!
100  *
101  * The seperate calls are sent to a callback function provided by the caller
102  * (the caller will usually call itself recursively). The callback function
103  * must be a command handler. Calling this function on a line with no list causes
104  * no action to be taken. You must provide a starting and ending parameter number
105  * where the range of the list can be found, useful if you have a terminating
106  * parameter as above which is actually not part of the list, or parameters
107  * before the actual list as well. This code is used by many functions which
108  * can function as "one to list" (see the RFC) */
109
110 int CommandParser::LoopCall(command_t* fn, char **parameters, int pcnt, userrec *u, int start, int end, int joins)
111 {
112         char plist[MAXBUF];
113         char *param;
114         char *pars[32];
115         char blog[32][MAXBUF];
116         char blog2[32][MAXBUF];
117         int j = 0, q = 0, total = 0, t = 0, t2 = 0, total2 = 0;
118         char keystr[MAXBUF];
119         char moo[MAXBUF];
120
121         for (int i = 0; i <32; i++)
122         {
123                 *blog[i] = 0;
124                 *blog2[i] = 0;
125         }
126
127         *moo = 0;
128         for (int i = 0; i <10; i++)
129         {
130                 if (!parameters[i])
131                 {
132                         parameters[i] = moo;
133                 }
134         }
135         if (joins)
136         {
137                 if (pcnt > 1) /* we have a key to copy */
138                 {
139                         strlcpy(keystr,parameters[1],MAXBUF);
140                 }
141         }
142
143         if (!parameters[start] || (!strchr(parameters[start],',')))
144         {
145                 return 0;
146         }
147
148         *plist = 0;
149
150         for (int i = start; i <= end; i++)
151         {
152                 if (parameters[i])
153                 {
154                         strlcat(plist,parameters[i],MAXBUF);
155                 }
156         }
157
158         j = 0;
159         param = plist;
160
161         t = strlen(plist);
162
163         for (int i = 0; i < t; i++)
164         {
165                 if (plist[i] == ',')
166                 {
167                         plist[i] = '\0';
168                         strlcpy(blog[j++],param,MAXBUF);
169                         param = plist+i+1;
170                         if ((unsigned int)j > Config->MaxTargets)
171                         {
172                                 WriteServ(u->fd,"407 %s %s :Too many targets in list, message not delivered.",u->nick,blog[j-1]);
173                                 return 1;
174                         }
175                 }
176         }
177
178         strlcpy(blog[j++],param,MAXBUF);
179         total = j;
180
181         if ((joins) && (keystr) && (total>0)) // more than one channel and is joining
182         {
183                 strcat(keystr,",");
184         }
185
186         if ((joins) && (keystr))
187         {
188                 if (strchr(keystr,','))
189                 {
190                         j = 0;
191                         param = keystr;
192                         t2 = strlen(keystr);
193
194                         for (int i = 0; i < t2; i++)
195                         {
196                                 if (keystr[i] == ',')
197                                 {
198                                         keystr[i] = '\0';
199                                         strlcpy(blog2[j++],param,MAXBUF);
200                                         param = keystr+i+1;
201                                 }
202                         }
203
204                         strlcpy(blog2[j++],param,MAXBUF);
205                         total2 = j;
206                 }
207         }
208
209         for (j = 0; j < total; j++)
210         {
211                 if (blog[j])
212                 {
213                         pars[0] = blog[j];
214                 }
215
216                 for (q = end; q < pcnt-1; q++)
217                 {
218                         if (parameters[q+1])
219                         {
220                                 pars[q-end+1] = parameters[q+1];
221                         }
222                 }
223
224                 if ((joins) && (parameters[1]))
225                 {
226                         if (pcnt > 1)
227                         {
228                                 pars[1] = blog2[j];
229                         }
230                         else
231                         {
232                                 pars[1] = NULL;
233                         }
234                 }
235
236                 /* repeatedly call the function with the hacked parameter list */
237                 if ((joins) && (pcnt > 1))
238                 {
239                         if (pars[1])
240                         {
241                                 // pars[1] already set up and containing key from blog2[j]
242                                 fn->Handle(pars,2,u);
243                         }
244                         else
245                         {
246                                 pars[1] = parameters[1];
247                                 fn->Handle(pars,2,u);
248                         }
249                 }
250                 else
251                 {
252                         fn->Handle(pars,pcnt-(end-start),u);
253                 }
254         }
255
256         return 1;
257 }
258
259 bool CommandParser::IsValidCommand(std::string &commandname, int pcnt, userrec * user)
260 {
261         nspace::hash_map<std::string,command_t*>::iterator n = cmdlist.find(commandname);
262
263         if (n != cmdlist.end())
264         {
265                 if ((pcnt>=n->second->min_params) && (n->second->source != "<core>"))
266                 {
267                         if ((strchr(user->modes,n->second->flags_needed)) || (!n->second->flags_needed))
268                         {
269                                 if (n->second->flags_needed)
270                                 {
271                                         if ((user->HasPermission(commandname)) || (is_uline(user->server)))
272                                         {
273                                                 return true;
274                                         }
275                                         else
276                                         {
277                                                 return false;
278                                         }
279                                 }
280
281                                 return true;
282                         }
283                 }
284         }
285
286         return false;
287 }
288
289 // calls a handler function for a command
290
291 void CommandParser::CallHandler(std::string &commandname,char **parameters, int pcnt, userrec *user)
292 {
293         nspace::hash_map<std::string,command_t*>::iterator n = cmdlist.find(commandname);
294
295         if (n != cmdlist.end())
296         {
297                 if (pcnt >= n->second->min_params)
298                 {
299                         if ((strchr(user->modes,n->second->flags_needed)) || (!n->second->flags_needed))
300                         {
301                                 if (n->second->flags_needed)
302                                 {
303                                         if ((user->HasPermission(commandname)) || (is_uline(user->server)))
304                                         {
305                                                 n->second->Handle(parameters,pcnt,user);
306                                         }
307                                         else
308                                         {
309                                                 if (!IS_LOCAL(user))
310                                                         WriteOpers("*** \2WARNING\2: Command '%s' not allowed for oper '%s', dropped.",commandname.c_str(),user->nick);
311                                         }
312                                 }
313                                 else
314                                 {
315                                         n->second->Handle(parameters,pcnt,user);
316                                 }
317                         }
318                 }
319         }
320 }
321
322 int CommandParser::ProcessParameters(char **command_p,char *parameters)
323 {
324         int j = 0;
325         int q = strlen(parameters);
326
327         if (!q)
328         {
329                 /* no parameters, command_p invalid! */
330                 return 0;
331         }
332
333         if (parameters[0] == ':')
334         {
335                 command_p[0] = parameters+1;
336                 return 1;
337         }
338
339         if (q)
340         {
341                 if ((strchr(parameters,' ')==NULL) || (parameters[0] == ':'))
342                 {
343                         /* only one parameter */
344                         command_p[0] = parameters;
345                         if (parameters[0] == ':')
346                         {
347                                 if (strchr(parameters,' ') != NULL)
348                                 {
349                                         command_p[0]++;
350                                 }
351                         }
352
353                         return 1;
354                 }
355         }
356
357         command_p[j++] = parameters;
358
359         for (int i = 0; i <= q; i++)
360         {
361                 if (parameters[i] == ' ')
362                 {
363                         command_p[j++] = parameters+i+1;
364                         parameters[i] = '\0';
365
366                         if (command_p[j-1][0] == ':')
367                         {
368                                 *command_p[j-1]++; /* remove dodgy ":" */
369                                 break;
370                                 /* parameter like this marks end of the sequence */
371                         }
372                 }
373         }
374
375         return j; /* returns total number of items in the list */
376 }
377
378 void CommandParser::ProcessCommand(userrec *user, char* cmd)
379 {
380         char *parameters;
381         char *command;
382         char *command_p[127];
383         char p[MAXBUF], temp[MAXBUF];
384         int j, items, cmd_found;
385         int total_params = 0;
386         unsigned int xl;
387
388         for (int i = 0; i < 127; i++)
389                 command_p[i] = NULL;
390
391         if (!user || !cmd || !*cmd)
392         {
393                 return;
394         }
395
396         xl = strlen(cmd);
397
398         if (xl > 2)
399         {
400                 for (unsigned int q = 0; q < xl - 1; q++)
401                 {
402                         if (cmd[q] == ' ')
403                         {
404                                 if (cmd[q+1] == ':')
405                                 {
406                                         total_params++;
407                                         // found a 'trailing', we dont count them after this.
408                                         break;
409                                 }
410                                 else
411                                         total_params++;
412                         }
413                 }
414         }
415
416         // another phidjit bug...
417         if (total_params > 126)
418         {
419                 *(strchr(cmd,' ')) = '\0';
420                 WriteServ(user->fd,"421 %s %s :Too many parameters given",user->nick,cmd);
421                 return;
422         }
423
424         strlcpy(temp,cmd,MAXBUF);
425
426         std::string tmp = cmd;
427
428         for (int i = 0; i <= MODCOUNT; i++)
429         {
430                 std::string oldtmp = tmp;
431                 modules[i]->OnServerRaw(tmp,true,user);
432                 if (oldtmp != tmp)
433                 {
434                         log(DEBUG,"A Module changed the input string!");
435                         log(DEBUG,"New string: %s",tmp.c_str());
436                         log(DEBUG,"Old string: %s",oldtmp.c_str());
437                         break;
438                 }
439         }
440
441         strlcpy(cmd,tmp.c_str(),MAXBUF);
442         strlcpy(temp,cmd,MAXBUF);
443
444         if (!strchr(cmd,' '))
445         {
446                 /*
447                  * no parameters, lets skip the formalities and not chop up
448                  * the string
449                  */
450                 log(DEBUG,"About to preprocess command with no params");
451                 items = 0;
452                 command_p[0] = NULL;
453                 parameters = NULL;
454                 unsigned int tl = strlen(cmd);
455                 for (unsigned int i = 0; i <= tl; i++)
456                 {
457                         cmd[i] = toupper(cmd[i]);
458                 }
459                 command = cmd;
460         }
461         else
462         {
463                 *cmd = 0;
464                 j = 0;
465
466                 unsigned int vl = strlen(temp);
467                 /* strip out extraneous linefeeds through mirc's crappy pasting (thanks Craig) */
468                 for (unsigned int i = 0; i < vl; i++)
469                 {
470                         if ((temp[i] != 10) && (temp[i] != 13) && (temp[i] != 0) && (temp[i] != 7))
471                         {
472                                 cmd[j++] = temp[i];
473                                 cmd[j] = 0;
474                         }
475                 }
476
477                 /* split the full string into a command plus parameters */
478                 parameters = p;
479                 p[0] = ' ';
480                 p[1] = 0;
481
482                 command = cmd;
483
484                 if (strchr(cmd,' '))
485                 {
486                         unsigned int cl = strlen(cmd);
487
488                         for (unsigned int i = 0; i <= cl; i++)
489                         {
490                                 /* capitalise the command ONLY, leave params intact */
491                                 cmd[i] = toupper(cmd[i]);
492                                 /* are we nearly there yet?! :P */
493                                 if (cmd[i] == ' ')
494                                 {
495                                         command = cmd;
496                                         parameters = cmd+i+1;
497                                         cmd[i] = '\0';
498                                         break;
499                                 }
500                         }
501                 }
502                 else
503                 {
504                         for (char* i = cmd; *i; i++)
505                         {
506                                 *i = toupper(*i);
507                         }
508                 }
509         }
510
511         if (strlen(command)>MAXCOMMAND)
512         {
513                 WriteServ(user->fd,"421 %s %s :Command too long",user->nick,command);
514                 return;
515         }
516
517         for (char* x = command; *x; x++)
518         {
519                 if (((*x < 'A') || (*x > 'Z')) && (*x != '.'))
520                 {
521                         if (((*x < '0') || (*x> '9')) && (*x != '-'))
522                         {
523                                 if (strchr("@!\"$%^&*(){}[]_=+;:'#~,<>/?\\|`",*x))
524                                 {
525                                         ServerInstance->stats->statsUnknown++;
526                                         WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
527                                         return;
528                                 }
529                         }
530                 }
531         }
532
533         std::string xcommand = command;
534         if ((user->registered != 7) && (xcommand == "SERVER"))
535         {
536                 kill_link(user,"Server connection to non-server port");
537                 return;
538         }
539         
540         /* Tweak by brain - why was this INSIDE the mainloop? */
541         if (parameters)
542         {
543                  if (parameters[0])
544                  {
545                          items = this->ProcessParameters(command_p,parameters);
546                  }
547                  else
548                  {
549                          items = 0;
550                          command_p[0] = NULL;
551                  }
552         }
553         else
554         {
555                 items = 0;
556                 command_p[0] = NULL;
557         }
558
559         int MOD_RESULT = 0;
560         FOREACH_RESULT(I_OnPreCommand,OnPreCommand(command,command_p,items,user,false));
561         if (MOD_RESULT == 1) {
562                 return;
563         }
564         
565         nspace::hash_map<std::string,command_t*>::iterator cm = cmdlist.find(xcommand);
566         
567         if (cm != cmdlist.end())
568         {
569                 if (user)
570                 {
571                         /* activity resets the ping pending timer */
572                         user->nping = TIME + user->pingmax;
573                         if ((items) < cm->second->min_params)
574                         {
575                                 log(DEBUG,"not enough parameters: %s %s",user->nick,command);
576                                 WriteServ(user->fd,"461 %s %s :Not enough parameters",user->nick,command);
577                                 return;
578                         }
579                         if ((!strchr(user->modes,cm->second->flags_needed)) && (cm->second->flags_needed))
580                         {
581                                 log(DEBUG,"permission denied: %s %s",user->nick,command);
582                                 WriteServ(user->fd,"481 %s :Permission Denied- You do not have the required operator privilages",user->nick);
583                                 cmd_found = 1;
584                                 return;
585                         }
586                         if ((cm->second->flags_needed) && (!user->HasPermission(xcommand)))
587                         {
588                                 log(DEBUG,"permission denied: %s %s",user->nick,command);
589                                 WriteServ(user->fd,"481 %s :Permission Denied- Oper type %s does not have access to command %s",user->nick,user->oper,command);
590                                 if (!IS_LOCAL(user))
591                                         WriteOpers("*** \2WARNING\2: Command '%s' not allowed for oper '%s', dropped.",command,user->nick);
592                                 cmd_found = 1;
593                                 return;
594                         }
595                         /* if the command isnt USER, PASS, or NICK, and nick is empty,
596                          * deny command! */
597                         if ((strncmp(command,"USER",4)) && (strncmp(command,"NICK",4)) && (strncmp(command,"PASS",4)))
598                         {
599                                 if ((!isnick(user->nick)) || (user->registered != 7))
600                                 {
601                                         log(DEBUG,"not registered: %s %s",user->nick,command);
602                                         WriteServ(user->fd,"451 %s :You have not registered",command);
603                                         return;
604                                 }
605                         }
606                         if ((user->registered == 7) && (!*user->oper) && (*Config->DisabledCommands))
607                         {
608                                 std::stringstream dcmds(Config->DisabledCommands);
609                                 std::string thiscmd;
610                                 while (dcmds >> thiscmd)
611                                 {
612                                         if (!strcasecmp(thiscmd.c_str(),command))
613                                         {
614                                                 // command is disabled!
615                                                 WriteServ(user->fd,"421 %s %s :This command has been disabled.",user->nick,command);
616                                                 return;
617                                         }
618                                 }
619                         }
620                         if ((user->registered == 7) || (!strncmp(command,"USER",4)) || (!strncmp(command,"NICK",4)) || (!strncmp(command,"PASS",4)))
621                         {
622                                 /* ikky /stats counters */
623                                 if (temp)
624                                 {
625                                         cm->second->use_count++;
626                                         cm->second->total_bytes+=strlen(temp);
627                                 }
628
629                                 int MOD_RESULT = 0;
630                                 FOREACH_RESULT(I_OnPreCommand,OnPreCommand(command,command_p,items,user,true));
631                                 if (MOD_RESULT == 1)
632                                 {
633                                         return;
634                                 }
635
636                                 /*
637                                  * WARNING: nothing may come after the
638                                  * command handler call, as the handler
639                                  * may free the user structure!
640                                  */
641
642                                 cm->second->Handle(command_p,items,user);
643                                 return;
644                         }
645                         else
646                         {
647                                 WriteServ(user->fd,"451 %s :You have not registered",command);
648                                 return;
649                         }
650                 }
651         }
652         else if (user)
653         {
654                 ServerInstance->stats->statsUnknown++;
655                 WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
656         }
657 }
658
659 bool CommandParser::RemoveCommands(const char* source)
660 {
661         bool go_again = true;
662
663         while (go_again)
664         {
665                 go_again = false;
666
667                 for (nspace::hash_map<std::string,command_t*>::iterator i = cmdlist.begin(); i != cmdlist.end(); i++)
668                 {
669                         command_t* x = i->second;
670                         if (x->source == std::string(source))
671                         {
672                                 log(DEBUG,"removecommands(%s) Removing dependent command: %s",x->source.c_str(),x->command.c_str());
673                                 cmdlist.erase(i);
674                                 go_again = true;
675                                 break;
676                         }
677                 }
678         }
679
680         return true;
681 }
682
683 void CommandParser::ProcessBuffer(const char* cmdbuf,userrec *user)
684 {
685         char cmd[MAXBUF];
686
687         if (!user)
688         {
689                 log(DEFAULT,"*** BUG *** process_buffer was given an invalid parameter");
690                 return;
691         }
692         if (!cmdbuf)
693         {
694                 log(DEFAULT,"*** BUG *** process_buffer was given an invalid parameter");
695                 return;
696         }
697         if (!cmdbuf[0])
698         {
699                 return;
700         }
701
702         while (*cmdbuf == ' ') cmdbuf++; // strip leading spaces
703
704         strlcpy(cmd,cmdbuf,MAXBUF);
705
706         if (!cmd[0])
707         {
708                 return;
709         }
710
711
712         /* XXX - This is ugly as sin, and incomprehensible - why are we doing this twice, for instance? --w00t */
713         int sl = strlen(cmd)-1;
714
715         if ((cmd[sl] == 13) || (cmd[sl] == 10))
716         {
717                 cmd[sl] = '\0';
718         }
719
720         sl = strlen(cmd)-1;
721
722         if ((cmd[sl] == 13) || (cmd[sl] == 10))
723         {
724                 cmd[sl] = '\0';
725         }
726
727         sl = strlen(cmd)-1;
728
729
730         while (cmd[sl] == ' ') // strip trailing spaces
731         {
732                 cmd[sl] = '\0';
733                 sl = strlen(cmd)-1;
734         }
735
736         if (!cmd[0])
737         {
738                 return;
739         }
740
741         log(DEBUG,"CMDIN: %s %s",user->nick,cmd);
742         tidystring(cmd);
743         if ((user) && (cmd))
744         {
745                 this->ProcessCommand(user,cmd);
746         }
747 }
748
749 bool CommandParser::CreateCommand(command_t *f)
750 {
751         /* create the command and push it onto the table */
752         if (cmdlist.find(f->command) == cmdlist.end())
753         {
754                 cmdlist[f->command] = f;
755                 log(DEBUG,"Added command %s (%lu parameters)",f->command.c_str(),(unsigned long)f->min_params);
756                 return true;
757         }
758         else return false;
759 }
760
761 CommandParser::CommandParser()
762 {
763         this->SetupCommandTable();
764 }
765
766 void CommandParser::SetupCommandTable()
767 {
768         this->CreateCommand(new cmd_user);
769         this->CreateCommand(new cmd_nick);
770         this->CreateCommand(new cmd_quit);
771         this->CreateCommand(new cmd_version);
772         this->CreateCommand(new cmd_ping);
773         this->CreateCommand(new cmd_pong);
774         this->CreateCommand(new cmd_admin);
775         this->CreateCommand(new cmd_privmsg);
776         this->CreateCommand(new cmd_info);
777         this->CreateCommand(new cmd_time);
778         this->CreateCommand(new cmd_whois);
779         this->CreateCommand(new cmd_wallops);
780         this->CreateCommand(new cmd_notice);
781         this->CreateCommand(new cmd_join);
782         this->CreateCommand(new cmd_names);
783         this->CreateCommand(new cmd_part);
784         this->CreateCommand(new cmd_kick);
785         this->CreateCommand(new cmd_mode);
786         this->CreateCommand(new cmd_topic);
787         this->CreateCommand(new cmd_who);
788         this->CreateCommand(new cmd_motd);
789         this->CreateCommand(new cmd_rules);
790         this->CreateCommand(new cmd_oper);
791         this->CreateCommand(new cmd_list);
792         this->CreateCommand(new cmd_die);
793         this->CreateCommand(new cmd_restart);
794         this->CreateCommand(new cmd_kill);
795         this->CreateCommand(new cmd_rehash);
796         this->CreateCommand(new cmd_lusers);
797         this->CreateCommand(new cmd_stats);
798         this->CreateCommand(new cmd_userhost);
799         this->CreateCommand(new cmd_away);
800         this->CreateCommand(new cmd_ison);
801         this->CreateCommand(new cmd_summon);
802         this->CreateCommand(new cmd_users);
803         this->CreateCommand(new cmd_invite);
804         this->CreateCommand(new cmd_pass);
805         this->CreateCommand(new cmd_trace);
806         this->CreateCommand(new cmd_whowas);
807         this->CreateCommand(new cmd_connect);
808         this->CreateCommand(new cmd_squit);
809         this->CreateCommand(new cmd_modules);
810         this->CreateCommand(new cmd_links);
811         this->CreateCommand(new cmd_map);
812         this->CreateCommand(new cmd_kline);
813         this->CreateCommand(new cmd_gline);
814         this->CreateCommand(new cmd_zline);
815         this->CreateCommand(new cmd_qline);
816         this->CreateCommand(new cmd_eline);
817         this->CreateCommand(new cmd_loadmodule);
818         this->CreateCommand(new cmd_unloadmodule);
819         this->CreateCommand(new cmd_server);
820         this->CreateCommand(new cmd_commands);
821 }
822