source: irc_commands.c @ a08e875

Last change on this file since a08e875 was 324c378, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-13T23:14:41Z

Move control channel autoconfiguration to irc_cmd_join() instead so that it
only triggers on channels created by the user. (And not at identify time,
which was causing odd problems on my test setup.)

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