source: irc_commands.c @ f5c0d8e

Last change on this file since f5c0d8e was f5c0d8e, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-31T20:06:14Z

Merge mainline stuff.

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