source: irc_commands.c @ b925666

Last change on this file since b925666 was 13fa2db, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-27T22:24:59Z

Don't crash when trying to join a channel with an invalid name.

  • Property mode set to 100644
File size: 19.0 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* IRC commands                                                         */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#define BITLBEE_CORE
27#include "bitlbee.h"
28#include "ipc.h"
29
30static void irc_cmd_pass( irc_t *irc, char **cmd )
31{
32        if( irc->status & USTATUS_LOGGED_IN )
33        {
34                char *send_cmd[] = { "identify", cmd[1], NULL };
35               
36                /* We're already logged in, this client seems to send the PASS
37                   command last. (Possibly it won't send it at all if it turns
38                   out we don't require it, which will break this feature.)
39                   Try to identify using the given password. */
40                return root_command( irc, send_cmd );
41        }
42        /* Handling in pre-logged-in state, first see if this server is
43           password-protected: */
44        else if( global.conf->auth_pass &&
45            ( strncmp( global.conf->auth_pass, "md5:", 4 ) == 0 ?
46                md5_verify_password( cmd[1], global.conf->auth_pass + 4 ) == 0 :
47                strcmp( cmd[1], global.conf->auth_pass ) == 0 ) )
48        {
49                irc->status |= USTATUS_AUTHORIZED;
50                irc_check_login( irc );
51        }
52        else if( global.conf->auth_pass )
53        {
54                irc_send_num( irc, 464, ":Incorrect password" );
55        }
56        else
57        {
58                /* Remember the password and try to identify after USER/NICK. */
59                irc_setpass( irc, cmd[1] );
60                irc_check_login( irc );
61        }
62}
63
64static void irc_cmd_user( irc_t *irc, char **cmd )
65{
66        irc->user->user = g_strdup( cmd[1] );
67        irc->user->fullname = g_strdup( cmd[4] );
68       
69        irc_check_login( irc );
70}
71
72static void irc_cmd_nick( irc_t *irc, char **cmd )
73{
74        irc_user_t *iu;
75       
76        if( ( iu = irc_user_by_name( irc, cmd[1] ) ) && iu != irc->user )
77        {
78                irc_send_num( irc, 433, "%s :This nick is already in use", cmd[1] );
79        }
80        else if( !nick_ok( cmd[1] ) )
81        {
82                /* [SH] Invalid characters. */
83                irc_send_num( irc, 432, "%s :This nick contains invalid characters", cmd[1] );
84        }
85        else if( irc->status & USTATUS_LOGGED_IN )
86        {
87                if( irc->status & USTATUS_IDENTIFIED )
88                {
89                        irc_setpass( irc, NULL );
90                        irc->status &= ~USTATUS_IDENTIFIED;
91                        irc_umode_set( irc, "-R", 1 );
92                        irc_usermsg( irc, "Changing nicks resets your identify status. "
93                                     "Re-identify or register a new account if you want "
94                                     "your configuration to be saved. See \x02help "
95                                     "nick_changes\x02." );
96                }
97               
98                irc_user_set_nick( irc->user, cmd[1] );
99        }
100        else
101        {
102                g_free( irc->user->nick );
103                irc->user->nick = g_strdup( cmd[1] );
104               
105                irc_check_login( irc );
106        }
107}
108
109static void irc_cmd_quit( irc_t *irc, char **cmd )
110{
111        if( cmd[1] && *cmd[1] )
112                irc_abort( irc, 0, "Quit: %s", cmd[1] );
113        else
114                irc_abort( irc, 0, "Leaving..." );
115}
116
117static void irc_cmd_ping( irc_t *irc, char **cmd )
118{
119        irc_write( irc, ":%s PONG %s :%s", irc->root->host,
120                   irc->root->host, cmd[1]?cmd[1]:irc->root->host );
121}
122
123static void irc_cmd_pong( irc_t *irc, char **cmd )
124{
125        /* We could check the value we get back from the user, but in
126           fact we don't care, we're just happy s/he's still alive. */
127        irc->last_pong = gettime();
128        irc->pinging = 0;
129}
130
131static void irc_cmd_join( irc_t *irc, char **cmd )
132{
133        char *comma, *s = cmd[1];
134       
135        while( s )
136        {
137                irc_channel_t *ic;
138               
139                if( ( comma = strchr( s, ',' ) ) )
140                        *comma = '\0';
141               
142                if( ( ic = irc_channel_by_name( irc, s ) ) == NULL &&
143                    ( ic = irc_channel_new( irc, s ) ) )
144                {
145                        if( strcmp( set_getstr( &ic->set, "type" ), "control" ) != 0 )
146                        {
147                                /* Autoconfiguration is for control channels only ATM. */
148                        }
149                        else if( bee_group_by_name( ic->irc->b, ic->name + 1, FALSE ) )
150                        {
151                                set_setstr( &ic->set, "group", ic->name + 1 );
152                                set_setstr( &ic->set, "fill_by", "group" );
153                        }
154                        else if( set_setstr( &ic->set, "protocol", ic->name + 1 ) )
155                        {
156                                set_setstr( &ic->set, "fill_by", "protocol" );
157                        }
158                        else if( set_setstr( &ic->set, "account", ic->name + 1 ) )
159                        {
160                                set_setstr( &ic->set, "fill_by", "account" );
161                        }
162                        else
163                        {
164                                /* The set commands above will run this already,
165                                   but if we didn't hit any, we have to fill the
166                                   channel with the default population. */
167                                bee_irc_channel_update( ic->irc, ic, NULL );
168                        }
169                }
170                else if( ic == NULL )
171                {
172                        irc_send_num( irc, 479, "%s :Invalid channel name", s );
173                        goto next;
174                }
175               
176                if( ic->flags & IRC_CHANNEL_JOINED )
177                        /* Dude, you're already there...
178                           RFC doesn't have any reply for that though? */
179                        goto next;
180               
181                if( ic->f->join && !ic->f->join( ic ) )
182                        /* The story is: FALSE either means the handler
183                           showed an error message, or is doing some work
184                           before the join should be confirmed. (In the
185                           latter case, the caller should take care of that
186                           confirmation.) TRUE means all's good, let the
187                           user join the channel right away. */
188                        goto next;
189               
190                irc_channel_add_user( ic, irc->user );
191               
192next:
193                if( comma )
194                {
195                        s = comma + 1;
196                        *comma = ',';
197                }
198                else
199                        break;
200        }
201}
202
203static void irc_cmd_names( irc_t *irc, char **cmd )
204{
205        irc_channel_t *ic;
206       
207        if( cmd[1] && ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
208                irc_send_names( ic );
209        /* With no args, we should show /names of all chans. Make the code
210           below work well if necessary.
211        else
212        {
213                GSList *l;
214               
215                for( l = irc->channels; l; l = l->next )
216                        irc_send_names( l->data );
217        }
218        */
219}
220
221static void irc_cmd_part( irc_t *irc, char **cmd )
222{
223        irc_channel_t *ic;
224       
225        if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
226        {
227                irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
228        }
229        else if( irc_channel_del_user( ic, irc->user, IRC_CDU_PART, cmd[2] ) )
230        {
231                if( ic->f->part )
232                        ic->f->part( ic, NULL );
233        }
234        else
235        {
236                irc_send_num( irc, 442, "%s :You're not on that channel", cmd[1] );
237        }
238}
239
240static void irc_cmd_whois( irc_t *irc, char **cmd )
241{
242        char *nick = cmd[1];
243        irc_user_t *iu = irc_user_by_name( irc, nick );
244       
245        if( iu )
246                irc_send_whois( iu );
247        else
248                irc_send_num( irc, 401, "%s :Nick does not exist", nick );
249}
250
251static void irc_cmd_whowas( irc_t *irc, char **cmd )
252{
253        /* For some reason irssi tries a whowas when whois fails. We can
254           ignore this, but then the user never gets a "user not found"
255           message from irssi which is a bit annoying. So just respond
256           with not-found and irssi users will get better error messages */
257       
258        irc_send_num( irc, 406, "%s :Nick does not exist", cmd[1] );
259        irc_send_num( irc, 369, "%s :End of WHOWAS", cmd[1] );
260}
261
262static void irc_cmd_motd( irc_t *irc, char **cmd )
263{
264        irc_send_motd( irc );
265}
266
267static void irc_cmd_mode( irc_t *irc, char **cmd )
268{
269        if( irc_channel_name_ok( cmd[1] ) )
270        {
271                irc_channel_t *ic;
272               
273                if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
274                        irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
275                else if( cmd[2] )
276                {
277                        if( *cmd[2] == '+' || *cmd[2] == '-' )
278                                irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] );
279                        else if( *cmd[2] == 'b' )
280                                irc_send_num( irc, 368, "%s :No bans possible", cmd[1] );
281                }
282                else
283                        irc_send_num( irc, 324, "%s +%s", cmd[1], ic->mode );
284        }
285        else
286        {
287                if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
288                {
289                        if( cmd[2] )
290                                irc_umode_set( irc, cmd[2], 0 );
291                        else
292                                irc_send_num( irc, 221, "+%s", irc->umode );
293                }
294                else
295                        irc_send_num( irc, 502, ":Don't touch their modes" );
296        }
297}
298
299static void irc_cmd_who( irc_t *irc, char **cmd )
300{
301        char *channel = cmd[1];
302        irc_channel_t *ic;
303       
304        if( !channel || *channel == '0' || *channel == '*' || !*channel )
305                irc_send_who( irc, irc->users, "**" );
306        else if( ( ic = irc_channel_by_name( irc, channel ) ) )
307                irc_send_who( irc, ic->users, channel );
308        else
309                irc_send_num( irc, 403, "%s :No such channel", channel );
310}
311
312static void irc_cmd_privmsg( irc_t *irc, char **cmd )
313{
314        irc_channel_t *ic;
315        irc_user_t *iu;
316       
317        if( !cmd[2] ) 
318        {
319                irc_send_num( irc, 412, ":No text to send" );
320                return;
321        }
322       
323        /* Don't treat CTCP actions as real CTCPs, just convert them right now. */
324        if( g_strncasecmp( cmd[2], "\001ACTION", 7 ) == 0 )
325        {
326                cmd[2] += 4;
327                memcpy( cmd[2], "/me", 3 );
328                if( cmd[2][strlen(cmd[2])-1] == '\001' )
329                        cmd[2][strlen(cmd[2])-1] = '\0';
330        }
331       
332        if( irc_channel_name_ok( cmd[1] ) &&
333            ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
334        {
335                if( cmd[2][0] == '\001' )
336                {
337                        /* CTCPs to channels? Nah. Maybe later. */
338                }
339                else if( ic->f->privmsg )
340                        ic->f->privmsg( ic, cmd[2] );
341        }
342        else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) )
343        {
344                if( cmd[2][0] == '\001' )
345                {
346                        char **ctcp;
347                       
348                        if( iu->f->ctcp == NULL )
349                                return;
350                        if( cmd[2][strlen(cmd[2])-1] == '\001' )
351                                cmd[2][strlen(cmd[2])-1] = '\0';
352                       
353                        ctcp = split_command_parts( cmd[2] + 1 );
354                        iu->f->ctcp( iu, ctcp );
355                }
356                else if( iu->f->privmsg )
357                {
358                        iu->last_channel = NULL;
359                        iu->f->privmsg( iu, cmd[2] );
360                }
361        }
362        else
363        {
364                irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] );
365        }
366}
367
368static void irc_cmd_notice( irc_t *irc, char **cmd )
369{
370        if( !cmd[2] ) 
371        {
372                irc_send_num( irc, 412, ":No text to send" );
373                return;
374        }
375       
376        /* At least for now just echo. IIRC some IRC clients use self-notices
377           for lag checks, so try to support that. */
378        if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
379                irc_send_msg( irc->user, "NOTICE", irc->user->nick, cmd[2], NULL );
380}
381
382static void irc_cmd_nickserv( irc_t *irc, char **cmd )
383{
384        /* [SH] This aliases the NickServ command to PRIVMSG root */
385        /* [TV] This aliases the NS command to PRIVMSG root as well */
386        root_command( irc, cmd + 1 );
387}
388
389
390
391static void irc_cmd_oper( irc_t *irc, char **cmd )
392{
393        if( global.conf->oper_pass &&
394            ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
395                md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
396                strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
397        {
398                irc_umode_set( irc, "+o", 1 );
399                irc_send_num( irc, 381, ":Password accepted" );
400        }
401        else
402        {
403                irc_send_num( irc, 432, ":Incorrect password" );
404        }
405}
406
407static void irc_cmd_invite( irc_t *irc, char **cmd )
408{
409        irc_channel_t *ic;
410        irc_user_t *iu;
411       
412        if( ( iu = irc_user_by_name( irc, cmd[1] ) ) == NULL )
413        {
414                irc_send_num( irc, 401, "%s :No such nick", cmd[1] );
415                return;
416        }
417        else if( ( ic = irc_channel_by_name( irc, cmd[2] ) ) == NULL )
418        {
419                irc_send_num( irc, 403, "%s :No such channel", cmd[2] );
420                return;
421        }
422       
423        if( !ic->f->invite )
424                irc_send_num( irc, 482, "%s :Can't invite people here", cmd[2] );
425        else if( ic->f->invite( ic, iu ) )
426                irc_send_num( irc, 341, "%s %s", iu->nick, ic->name );
427}
428
429static void irc_cmd_userhost( irc_t *irc, char **cmd )
430{
431        int i;
432       
433        /* [TV] Usable USERHOST-implementation according to
434                RFC1459. Without this, mIRC shows an error
435                while connecting, and the used way of rejecting
436                breaks standards.
437        */
438       
439        for( i = 1; cmd[i]; i ++ )
440        {
441                irc_user_t *iu = irc_user_by_name( irc, cmd[i] );
442               
443                if( iu )
444                        irc_send_num( irc, 302, ":%s=%c%s@%s", iu->nick,
445                                      irc_user_get_away( iu ) ? '-' : '+',
446                                      iu->user, iu->host );
447        }
448}
449
450static void irc_cmd_ison( irc_t *irc, char **cmd )
451{
452        char buff[IRC_MAX_LINE];
453        int lenleft, i;
454       
455        buff[0] = '\0';
456       
457        /* [SH] Leave room for : and \0 */
458        lenleft = IRC_MAX_LINE - 2;
459       
460        for( i = 1; cmd[i]; i ++ )
461        {
462                char *this, *next;
463               
464                this = cmd[i];
465                while( *this )
466                {
467                        irc_user_t *iu;
468                       
469                        if( ( next = strchr( this, ' ' ) ) )
470                                *next = 0;
471                       
472                        if( ( iu = irc_user_by_name( irc, this ) ) &&
473                            iu->bu && iu->bu->flags & BEE_USER_ONLINE )
474                        {
475                                lenleft -= strlen( iu->nick ) + 1;
476                               
477                                if( lenleft < 0 )
478                                        break;
479                               
480                                strcat( buff, iu->nick );
481                                strcat( buff, " " );
482                        }
483                       
484                        if( next )
485                        {
486                                *next = ' ';
487                                this = next + 1;
488                        }
489                        else
490                        {
491                                break;
492                        }   
493                }
494               
495                /* *sigh* */
496                if( lenleft < 0 )
497                        break;
498        }
499       
500        if( strlen( buff ) > 0 )
501                buff[strlen(buff)-1] = '\0';
502       
503        irc_send_num( irc, 303, ":%s", buff );
504}
505
506static void irc_cmd_watch( irc_t *irc, char **cmd )
507{
508        int i;
509       
510        /* Obviously we could also mark a user structure as being
511           watched, but what if the WATCH command is sent right
512           after connecting? The user won't exist yet then... */
513        for( i = 1; cmd[i]; i ++ )
514        {
515                char *nick;
516                irc_user_t *iu;
517               
518                if( !cmd[i][0] || !cmd[i][1] )
519                        break;
520               
521                nick = g_strdup( cmd[i] + 1 );
522                nick_lc( nick );
523               
524                iu = irc_user_by_name( irc, nick );
525               
526                if( cmd[i][0] == '+' )
527                {
528                        if( !g_hash_table_lookup( irc->watches, nick ) )
529                                g_hash_table_insert( irc->watches, nick, nick );
530                       
531                        if( iu && iu->bu && iu->bu->flags & BEE_USER_ONLINE )
532                                irc_send_num( irc, 604, "%s %s %s %d :%s", iu->nick, iu->user,
533                                              iu->host, (int) time( NULL ), "is online" );
534                        else
535                                irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*",
536                                              (int) time( NULL ), "is offline" );
537                }
538                else if( cmd[i][0] == '-' )
539                {
540                        gpointer okey, ovalue;
541                       
542                        if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
543                        {
544                                g_hash_table_remove( irc->watches, okey );
545                                g_free( okey );
546                               
547                                irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
548                        }
549                }
550        }
551}
552
553static void irc_cmd_topic( irc_t *irc, char **cmd )
554{
555        irc_channel_t *ic = irc_channel_by_name( irc, cmd[1] );
556        const char *new = cmd[2];
557       
558        if( ic == NULL )
559        {
560                irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
561        }
562        else if( new )
563        {
564                if( ic->f->topic == NULL )
565                        irc_send_num( irc, 482, "%s :Can't change this channel's topic", ic->name );
566                else if( ic->f->topic( ic, new ) )
567                        irc_send_topic( ic, TRUE );
568        }
569        else
570        {
571                irc_send_topic( ic, FALSE );
572        }
573}
574
575static void irc_cmd_away( irc_t *irc, char **cmd )
576{
577        if( cmd[1] && *cmd[1] )
578        {
579                char away[strlen(cmd[1])+1];
580                int i, j;
581               
582                /* Copy away string, but skip control chars. Mainly because
583                   Jabber really doesn't like them. */
584                for( i = j = 0; cmd[1][i]; i ++ )
585                        if( ( away[j] = cmd[1][i] ) >= ' ' )
586                                j ++;
587                away[j] = '\0';
588               
589                irc_send_num( irc, 306, ":You're now away: %s", away );
590                set_setstr( &irc->b->set, "away", away );
591        }
592        else
593        {
594                irc_send_num( irc, 305, ":Welcome back" );
595                set_setstr( &irc->b->set, "away", NULL );
596        }
597}
598
599static void irc_cmd_version( irc_t *irc, char **cmd )
600{
601        irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ",
602                      BITLBEE_VERSION, irc->root->host, ARCH, CPU );
603}
604
605static void irc_cmd_completions( irc_t *irc, char **cmd )
606{
607        help_t *h;
608        set_t *s;
609        int i;
610       
611        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS OK" );
612       
613        for( i = 0; commands[i].command; i ++ )
614                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS %s", commands[i].command );
615       
616        for( h = global.help; h; h = h->next )
617                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS help %s", h->title );
618       
619        for( s = irc->b->set; s; s = s->next )
620                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS set %s", s->key );
621       
622        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS END" );
623}
624
625static void irc_cmd_rehash( irc_t *irc, char **cmd )
626{
627        if( global.conf->runmode == RUNMODE_INETD )
628                ipc_master_cmd_rehash( NULL, NULL );
629        else
630                ipc_to_master( cmd );
631       
632        irc_send_num( irc, 382, "%s :Rehashing", global.conf_file );
633}
634
635static const command_t irc_commands[] = {
636        { "pass",        1, irc_cmd_pass,        0 },
637        { "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
638        { "nick",        1, irc_cmd_nick,        0 },
639        { "quit",        0, irc_cmd_quit,        0 },
640        { "ping",        0, irc_cmd_ping,        0 },
641        { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
642        { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
643        { "names",       1, irc_cmd_names,       IRC_CMD_LOGGED_IN },
644        { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
645        { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
646        { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
647        { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
648        { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
649        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
650        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
651        { "notice",      1, irc_cmd_notice,      IRC_CMD_LOGGED_IN },
652        { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
653        { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
654        { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
655        { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
656        { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
657        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
658        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
659        { "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
660        { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
661        { "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
662        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
663        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
664        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
665        { "wallops",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
666        { "wall",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
667        { "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY },
668        { "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
669        { "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
670        { NULL }
671};
672
673void irc_exec( irc_t *irc, char *cmd[] )
674{       
675        int i, n_arg;
676       
677        if( !cmd[0] )
678                return;
679       
680        for( i = 0; irc_commands[i].command; i++ )
681                if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 )
682                {
683                        /* There should be no typo in the next line: */
684                        for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --;
685                       
686                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
687                        {
688                                irc_send_num( irc, 462, ":Only allowed before logging in" );
689                        }
690                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
691                        {
692                                irc_send_num( irc, 451, ":Register first" );
693                        }
694                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
695                        {
696                                irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" );
697                        }
698                        else if( n_arg < irc_commands[i].required_parameters )
699                        {
700                                irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] );
701                        }
702                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
703                        {
704                                /* IPC doesn't make sense in inetd mode,
705                                    but the function will catch that. */
706                                ipc_to_master( cmd );
707                        }
708                        else
709                        {
710                                irc_commands[i].execute( irc, cmd );
711                        }
712                       
713                        return;
714                }
715       
716        if( irc->status >= USTATUS_LOGGED_IN )
717                irc_send_num( irc, 421, "%s :Unknown command", cmd[0] );
718}
Note: See TracBrowser for help on using the repository browser.