source: irc_commands.c @ f486006

Last change on this file since f486006 was 8e9e2b7, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-10-03T02:45:26Z

Merging mainline, which includes a huge msnp13 merge.

Not 100% sure about the OpenSSL merge, should double check that but I'm
currently offline.

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