source: irc_commands.c @ 9564e55

Last change on this file since 9564e55 was 9564e55, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-11-22T13:17:45Z

Allow omitting the password argument to "account add", to then separately
enter the password using the /OPER command (which will not echo to the
screen and/or logs).

It's a fairly ugly hack but the improved password security is worth it
IMHO.

  • Property mode set to 100644
File size: 19.9 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        account_t *a;
404       
405        /* /OPER can now also be used to enter IM passwords without echoing.
406           It's a hack but the extra password security is worth it. */
407        for( a = irc->b->accounts; a; a = a->next )
408                if( strcmp( a->pass, PASSWORD_PENDING ) == 0 )
409                {
410                        set_setstr( &a->set, "password", cmd[2] );
411                        return;
412                }
413       
414        if( global.conf->oper_pass &&
415            ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
416                md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
417                strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
418        {
419                irc_umode_set( irc, "+o", 1 );
420                irc_send_num( irc, 381, ":Password accepted" );
421        }
422        else
423        {
424                irc_send_num( irc, 432, ":Incorrect password" );
425        }
426}
427
428static void irc_cmd_invite( irc_t *irc, char **cmd )
429{
430        irc_channel_t *ic;
431        irc_user_t *iu;
432       
433        if( ( iu = irc_user_by_name( irc, cmd[1] ) ) == NULL )
434        {
435                irc_send_num( irc, 401, "%s :No such nick", cmd[1] );
436                return;
437        }
438        else if( ( ic = irc_channel_by_name( irc, cmd[2] ) ) == NULL )
439        {
440                irc_send_num( irc, 403, "%s :No such channel", cmd[2] );
441                return;
442        }
443       
444        if( !ic->f->invite )
445                irc_send_num( irc, 482, "%s :Can't invite people here", cmd[2] );
446        else if( ic->f->invite( ic, iu ) )
447                irc_send_num( irc, 341, "%s %s", iu->nick, ic->name );
448}
449
450static void irc_cmd_userhost( irc_t *irc, char **cmd )
451{
452        int i;
453       
454        /* [TV] Usable USERHOST-implementation according to
455                RFC1459. Without this, mIRC shows an error
456                while connecting, and the used way of rejecting
457                breaks standards.
458        */
459       
460        for( i = 1; cmd[i]; i ++ )
461        {
462                irc_user_t *iu = irc_user_by_name( irc, cmd[i] );
463               
464                if( iu )
465                        irc_send_num( irc, 302, ":%s=%c%s@%s", iu->nick,
466                                      irc_user_get_away( iu ) ? '-' : '+',
467                                      iu->user, iu->host );
468        }
469}
470
471static void irc_cmd_ison( irc_t *irc, char **cmd )
472{
473        char buff[IRC_MAX_LINE];
474        int lenleft, i;
475       
476        buff[0] = '\0';
477       
478        /* [SH] Leave room for : and \0 */
479        lenleft = IRC_MAX_LINE - 2;
480       
481        for( i = 1; cmd[i]; i ++ )
482        {
483                char *this, *next;
484               
485                this = cmd[i];
486                while( *this )
487                {
488                        irc_user_t *iu;
489                       
490                        if( ( next = strchr( this, ' ' ) ) )
491                                *next = 0;
492                       
493                        if( ( iu = irc_user_by_name( irc, this ) ) &&
494                            iu->bu && iu->bu->flags & BEE_USER_ONLINE )
495                        {
496                                lenleft -= strlen( iu->nick ) + 1;
497                               
498                                if( lenleft < 0 )
499                                        break;
500                               
501                                strcat( buff, iu->nick );
502                                strcat( buff, " " );
503                        }
504                       
505                        if( next )
506                        {
507                                *next = ' ';
508                                this = next + 1;
509                        }
510                        else
511                        {
512                                break;
513                        }   
514                }
515               
516                /* *sigh* */
517                if( lenleft < 0 )
518                        break;
519        }
520       
521        if( strlen( buff ) > 0 )
522                buff[strlen(buff)-1] = '\0';
523       
524        irc_send_num( irc, 303, ":%s", buff );
525}
526
527static void irc_cmd_watch( irc_t *irc, char **cmd )
528{
529        int i;
530       
531        /* Obviously we could also mark a user structure as being
532           watched, but what if the WATCH command is sent right
533           after connecting? The user won't exist yet then... */
534        for( i = 1; cmd[i]; i ++ )
535        {
536                char *nick;
537                irc_user_t *iu;
538               
539                if( !cmd[i][0] || !cmd[i][1] )
540                        break;
541               
542                nick = g_strdup( cmd[i] + 1 );
543                nick_lc( nick );
544               
545                iu = irc_user_by_name( irc, nick );
546               
547                if( cmd[i][0] == '+' )
548                {
549                        if( !g_hash_table_lookup( irc->watches, nick ) )
550                                g_hash_table_insert( irc->watches, nick, nick );
551                       
552                        if( iu && iu->bu && iu->bu->flags & BEE_USER_ONLINE )
553                                irc_send_num( irc, 604, "%s %s %s %d :%s", iu->nick, iu->user,
554                                              iu->host, (int) time( NULL ), "is online" );
555                        else
556                                irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*",
557                                              (int) time( NULL ), "is offline" );
558                }
559                else if( cmd[i][0] == '-' )
560                {
561                        gpointer okey, ovalue;
562                       
563                        if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
564                        {
565                                g_hash_table_remove( irc->watches, okey );
566                                g_free( okey );
567                               
568                                irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
569                        }
570                }
571        }
572}
573
574static void irc_cmd_topic( irc_t *irc, char **cmd )
575{
576        irc_channel_t *ic = irc_channel_by_name( irc, cmd[1] );
577        const char *new = cmd[2];
578       
579        if( ic == NULL )
580        {
581                irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
582        }
583        else if( new )
584        {
585                if( ic->f->topic == NULL )
586                        irc_send_num( irc, 482, "%s :Can't change this channel's topic", ic->name );
587                else if( ic->f->topic( ic, new ) )
588                        irc_send_topic( ic, TRUE );
589        }
590        else
591        {
592                irc_send_topic( ic, FALSE );
593        }
594}
595
596static void irc_cmd_away( irc_t *irc, char **cmd )
597{
598        if( cmd[1] && *cmd[1] )
599        {
600                char away[strlen(cmd[1])+1];
601                int i, j;
602               
603                /* Copy away string, but skip control chars. Mainly because
604                   Jabber really doesn't like them. */
605                for( i = j = 0; cmd[1][i]; i ++ )
606                        if( ( away[j] = cmd[1][i] ) >= ' ' )
607                                j ++;
608                away[j] = '\0';
609               
610                irc_send_num( irc, 306, ":You're now away: %s", away );
611                set_setstr( &irc->b->set, "away", away );
612        }
613        else
614        {
615                irc_send_num( irc, 305, ":Welcome back" );
616                set_setstr( &irc->b->set, "away", NULL );
617        }
618}
619
620static void irc_cmd_list( irc_t *irc, char **cmd )
621{
622        GSList *l;
623       
624        for( l = irc->channels; l; l = l->next )
625        {
626                irc_channel_t *ic = l->data;
627               
628                irc_send_num( irc, 322, "%s %d :%s",
629                              ic->name, g_slist_length( ic->users ), ic->topic ? : "" );
630        }
631        irc_send_num( irc, 323, ":%s", "End of /LIST" );
632}
633
634static void irc_cmd_version( irc_t *irc, char **cmd )
635{
636        irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ",
637                      BITLBEE_VERSION, irc->root->host, ARCH, CPU );
638}
639
640static void irc_cmd_completions( irc_t *irc, char **cmd )
641{
642        help_t *h;
643        set_t *s;
644        int i;
645       
646        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS OK" );
647       
648        for( i = 0; root_commands[i].command; i ++ )
649                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS %s", root_commands[i].command );
650       
651        for( h = global.help; h; h = h->next )
652                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS help %s", h->title );
653       
654        for( s = irc->b->set; s; s = s->next )
655                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS set %s", s->key );
656       
657        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS END" );
658}
659
660static void irc_cmd_rehash( irc_t *irc, char **cmd )
661{
662        if( global.conf->runmode == RUNMODE_INETD )
663                ipc_master_cmd_rehash( NULL, NULL );
664        else
665                ipc_to_master( cmd );
666       
667        irc_send_num( irc, 382, "%s :Rehashing", global.conf_file );
668}
669
670static const command_t irc_commands[] = {
671        { "pass",        1, irc_cmd_pass,        0 },
672        { "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
673        { "nick",        1, irc_cmd_nick,        0 },
674        { "quit",        0, irc_cmd_quit,        0 },
675        { "ping",        0, irc_cmd_ping,        0 },
676        { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
677        { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
678        { "names",       1, irc_cmd_names,       IRC_CMD_LOGGED_IN },
679        { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
680        { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
681        { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
682        { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
683        { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
684        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
685        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
686        { "notice",      1, irc_cmd_notice,      IRC_CMD_LOGGED_IN },
687        { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
688        { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
689        { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
690        { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
691        { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
692        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
693        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
694        { "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
695        { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
696        { "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
697        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
698        { "list",        0, irc_cmd_list,        IRC_CMD_LOGGED_IN },
699        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
700        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
701        { "wallops",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
702        { "wall",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
703        { "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY },
704        { "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
705        { "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
706        { NULL }
707};
708
709void irc_exec( irc_t *irc, char *cmd[] )
710{       
711        int i, n_arg;
712       
713        if( !cmd[0] )
714                return;
715       
716        for( i = 0; irc_commands[i].command; i++ )
717                if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 )
718                {
719                        /* There should be no typo in the next line: */
720                        for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --;
721                       
722                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
723                        {
724                                irc_send_num( irc, 462, ":Only allowed before logging in" );
725                        }
726                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
727                        {
728                                irc_send_num( irc, 451, ":Register first" );
729                        }
730                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
731                        {
732                                irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" );
733                        }
734                        else if( n_arg < irc_commands[i].required_parameters )
735                        {
736                                irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] );
737                        }
738                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
739                        {
740                                /* IPC doesn't make sense in inetd mode,
741                                    but the function will catch that. */
742                                ipc_to_master( cmd );
743                        }
744                        else
745                        {
746                                irc_commands[i].execute( irc, cmd );
747                        }
748                       
749                        return;
750                }
751       
752        if( irc->status >= USTATUS_LOGGED_IN )
753                irc_send_num( irc, 421, "%s :Unknown command", cmd[0] );
754}
Note: See TracBrowser for help on using the repository browser.