source: irc_commands.c @ d93c0eb9

Last change on this file since d93c0eb9 was daae10f, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-07T16:33:02Z

OpenSolaris (non-gcc) fixes, patches from Dagobert Michelsen <dam@…>
with some changes.

  • Property mode set to 100644
File size: 19.4 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       
305        if( !channel || *channel == '0' || *channel == '*' || !*channel )
306                irc_send_who( irc, irc->users, "**" );
307        else if( ( ic = irc_channel_by_name( irc, channel ) ) )
308                irc_send_who( irc, ic->users, channel );
309        else
310                irc_send_num( irc, 403, "%s :No such channel", channel );
311}
312
313static void irc_cmd_privmsg( irc_t *irc, char **cmd )
314{
315        irc_channel_t *ic;
316        irc_user_t *iu;
317       
318        if( !cmd[2] ) 
319        {
320                irc_send_num( irc, 412, ":No text to send" );
321                return;
322        }
323       
324        /* Don't treat CTCP actions as real CTCPs, just convert them right now. */
325        if( g_strncasecmp( cmd[2], "\001ACTION", 7 ) == 0 )
326        {
327                cmd[2] += 4;
328                memcpy( cmd[2], "/me", 3 );
329                if( cmd[2][strlen(cmd[2])-1] == '\001' )
330                        cmd[2][strlen(cmd[2])-1] = '\0';
331        }
332       
333        if( irc_channel_name_ok( cmd[1] ) &&
334            ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
335        {
336                if( cmd[2][0] == '\001' )
337                {
338                        /* CTCPs to channels? Nah. Maybe later. */
339                }
340                else if( ic->f->privmsg )
341                        ic->f->privmsg( ic, cmd[2] );
342        }
343        else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) )
344        {
345                if( cmd[2][0] == '\001' )
346                {
347                        char **ctcp;
348                       
349                        if( iu->f->ctcp == NULL )
350                                return;
351                        if( cmd[2][strlen(cmd[2])-1] == '\001' )
352                                cmd[2][strlen(cmd[2])-1] = '\0';
353                       
354                        ctcp = split_command_parts( cmd[2] + 1 );
355                        iu->f->ctcp( iu, ctcp );
356                }
357                else if( iu->f->privmsg )
358                {
359                        iu->last_channel = NULL;
360                        iu->f->privmsg( iu, cmd[2] );
361                }
362        }
363        else
364        {
365                irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] );
366        }
367}
368
369static void irc_cmd_notice( irc_t *irc, char **cmd )
370{
371        if( !cmd[2] ) 
372        {
373                irc_send_num( irc, 412, ":No text to send" );
374                return;
375        }
376       
377        /* At least for now just echo. IIRC some IRC clients use self-notices
378           for lag checks, so try to support that. */
379        if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
380                irc_send_msg( irc->user, "NOTICE", irc->user->nick, cmd[2], NULL );
381}
382
383static void irc_cmd_nickserv( irc_t *irc, char **cmd )
384{
385        /* [SH] This aliases the NickServ command to PRIVMSG root */
386        /* [TV] This aliases the NS command to PRIVMSG root as well */
387        root_command( irc, cmd + 1 );
388}
389
390
391
392static void irc_cmd_oper( irc_t *irc, char **cmd )
393{
394        if( global.conf->oper_pass &&
395            ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
396                md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
397                strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
398        {
399                irc_umode_set( irc, "+o", 1 );
400                irc_send_num( irc, 381, ":Password accepted" );
401        }
402        else
403        {
404                irc_send_num( irc, 432, ":Incorrect password" );
405        }
406}
407
408static void irc_cmd_invite( irc_t *irc, char **cmd )
409{
410        irc_channel_t *ic;
411        irc_user_t *iu;
412       
413        if( ( iu = irc_user_by_name( irc, cmd[1] ) ) == NULL )
414        {
415                irc_send_num( irc, 401, "%s :No such nick", cmd[1] );
416                return;
417        }
418        else if( ( ic = irc_channel_by_name( irc, cmd[2] ) ) == NULL )
419        {
420                irc_send_num( irc, 403, "%s :No such channel", cmd[2] );
421                return;
422        }
423       
424        if( !ic->f->invite )
425                irc_send_num( irc, 482, "%s :Can't invite people here", cmd[2] );
426        else if( ic->f->invite( ic, iu ) )
427                irc_send_num( irc, 341, "%s %s", iu->nick, ic->name );
428}
429
430static void irc_cmd_userhost( irc_t *irc, char **cmd )
431{
432        int i;
433       
434        /* [TV] Usable USERHOST-implementation according to
435                RFC1459. Without this, mIRC shows an error
436                while connecting, and the used way of rejecting
437                breaks standards.
438        */
439       
440        for( i = 1; cmd[i]; i ++ )
441        {
442                irc_user_t *iu = irc_user_by_name( irc, cmd[i] );
443               
444                if( iu )
445                        irc_send_num( irc, 302, ":%s=%c%s@%s", iu->nick,
446                                      irc_user_get_away( iu ) ? '-' : '+',
447                                      iu->user, iu->host );
448        }
449}
450
451static void irc_cmd_ison( irc_t *irc, char **cmd )
452{
453        char buff[IRC_MAX_LINE];
454        int lenleft, i;
455       
456        buff[0] = '\0';
457       
458        /* [SH] Leave room for : and \0 */
459        lenleft = IRC_MAX_LINE - 2;
460       
461        for( i = 1; cmd[i]; i ++ )
462        {
463                char *this, *next;
464               
465                this = cmd[i];
466                while( *this )
467                {
468                        irc_user_t *iu;
469                       
470                        if( ( next = strchr( this, ' ' ) ) )
471                                *next = 0;
472                       
473                        if( ( iu = irc_user_by_name( irc, this ) ) &&
474                            iu->bu && iu->bu->flags & BEE_USER_ONLINE )
475                        {
476                                lenleft -= strlen( iu->nick ) + 1;
477                               
478                                if( lenleft < 0 )
479                                        break;
480                               
481                                strcat( buff, iu->nick );
482                                strcat( buff, " " );
483                        }
484                       
485                        if( next )
486                        {
487                                *next = ' ';
488                                this = next + 1;
489                        }
490                        else
491                        {
492                                break;
493                        }   
494                }
495               
496                /* *sigh* */
497                if( lenleft < 0 )
498                        break;
499        }
500       
501        if( strlen( buff ) > 0 )
502                buff[strlen(buff)-1] = '\0';
503       
504        irc_send_num( irc, 303, ":%s", buff );
505}
506
507static void irc_cmd_watch( irc_t *irc, char **cmd )
508{
509        int i;
510       
511        /* Obviously we could also mark a user structure as being
512           watched, but what if the WATCH command is sent right
513           after connecting? The user won't exist yet then... */
514        for( i = 1; cmd[i]; i ++ )
515        {
516                char *nick;
517                irc_user_t *iu;
518               
519                if( !cmd[i][0] || !cmd[i][1] )
520                        break;
521               
522                nick = g_strdup( cmd[i] + 1 );
523                nick_lc( nick );
524               
525                iu = irc_user_by_name( irc, nick );
526               
527                if( cmd[i][0] == '+' )
528                {
529                        if( !g_hash_table_lookup( irc->watches, nick ) )
530                                g_hash_table_insert( irc->watches, nick, nick );
531                       
532                        if( iu && iu->bu && iu->bu->flags & BEE_USER_ONLINE )
533                                irc_send_num( irc, 604, "%s %s %s %d :%s", iu->nick, iu->user,
534                                              iu->host, (int) time( NULL ), "is online" );
535                        else
536                                irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*",
537                                              (int) time( NULL ), "is offline" );
538                }
539                else if( cmd[i][0] == '-' )
540                {
541                        gpointer okey, ovalue;
542                       
543                        if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
544                        {
545                                g_hash_table_remove( irc->watches, okey );
546                                g_free( okey );
547                               
548                                irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
549                        }
550                }
551        }
552}
553
554static void irc_cmd_topic( irc_t *irc, char **cmd )
555{
556        irc_channel_t *ic = irc_channel_by_name( irc, cmd[1] );
557        const char *new = cmd[2];
558       
559        if( ic == NULL )
560        {
561                irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
562        }
563        else if( new )
564        {
565                if( ic->f->topic == NULL )
566                        irc_send_num( irc, 482, "%s :Can't change this channel's topic", ic->name );
567                else if( ic->f->topic( ic, new ) )
568                        irc_send_topic( ic, TRUE );
569        }
570        else
571        {
572                irc_send_topic( ic, FALSE );
573        }
574}
575
576static void irc_cmd_away( irc_t *irc, char **cmd )
577{
578        if( cmd[1] && *cmd[1] )
579        {
580                char away[strlen(cmd[1])+1];
581                int i, j;
582               
583                /* Copy away string, but skip control chars. Mainly because
584                   Jabber really doesn't like them. */
585                for( i = j = 0; cmd[1][i]; i ++ )
586                        if( ( away[j] = cmd[1][i] ) >= ' ' )
587                                j ++;
588                away[j] = '\0';
589               
590                irc_send_num( irc, 306, ":You're now away: %s", away );
591                set_setstr( &irc->b->set, "away", away );
592        }
593        else
594        {
595                irc_send_num( irc, 305, ":Welcome back" );
596                set_setstr( &irc->b->set, "away", NULL );
597        }
598}
599
600static void irc_cmd_list( irc_t *irc, char **cmd )
601{
602        GSList *l;
603       
604        for( l = irc->channels; l; l = l->next )
605        {
606                irc_channel_t *ic = l->data;
607               
608                irc_send_num( irc, 322, "%s %d :%s",
609                              ic->name, g_slist_length( ic->users ), ic->topic ? : "" );
610        }
611        irc_send_num( irc, 323, ":%s", "End of /LIST" );
612}
613
614static void irc_cmd_version( irc_t *irc, char **cmd )
615{
616        irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ",
617                      BITLBEE_VERSION, irc->root->host, ARCH, CPU );
618}
619
620static void irc_cmd_completions( irc_t *irc, char **cmd )
621{
622        help_t *h;
623        set_t *s;
624        int i;
625       
626        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS OK" );
627       
628        for( i = 0; commands[i].command; i ++ )
629                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS %s", commands[i].command );
630       
631        for( h = global.help; h; h = h->next )
632                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS help %s", h->title );
633       
634        for( s = irc->b->set; s; s = s->next )
635                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS set %s", s->key );
636       
637        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS END" );
638}
639
640static void irc_cmd_rehash( irc_t *irc, char **cmd )
641{
642        if( global.conf->runmode == RUNMODE_INETD )
643                ipc_master_cmd_rehash( NULL, NULL );
644        else
645                ipc_to_master( cmd );
646       
647        irc_send_num( irc, 382, "%s :Rehashing", global.conf_file );
648}
649
650static const command_t irc_commands[] = {
651        { "pass",        1, irc_cmd_pass,        0 },
652        { "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
653        { "nick",        1, irc_cmd_nick,        0 },
654        { "quit",        0, irc_cmd_quit,        0 },
655        { "ping",        0, irc_cmd_ping,        0 },
656        { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
657        { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
658        { "names",       1, irc_cmd_names,       IRC_CMD_LOGGED_IN },
659        { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
660        { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
661        { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
662        { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
663        { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
664        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
665        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
666        { "notice",      1, irc_cmd_notice,      IRC_CMD_LOGGED_IN },
667        { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
668        { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
669        { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
670        { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
671        { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
672        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
673        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
674        { "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
675        { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
676        { "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
677        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
678        { "list",        0, irc_cmd_list,        IRC_CMD_LOGGED_IN },
679        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
680        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
681        { "wallops",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
682        { "wall",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
683        { "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY },
684        { "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
685        { "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
686        { NULL }
687};
688
689void irc_exec( irc_t *irc, char *cmd[] )
690{       
691        int i, n_arg;
692       
693        if( !cmd[0] )
694                return;
695       
696        for( i = 0; irc_commands[i].command; i++ )
697                if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 )
698                {
699                        /* There should be no typo in the next line: */
700                        for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --;
701                       
702                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
703                        {
704                                irc_send_num( irc, 462, ":Only allowed before logging in" );
705                        }
706                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
707                        {
708                                irc_send_num( irc, 451, ":Register first" );
709                        }
710                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
711                        {
712                                irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" );
713                        }
714                        else if( n_arg < irc_commands[i].required_parameters )
715                        {
716                                irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] );
717                        }
718                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
719                        {
720                                /* IPC doesn't make sense in inetd mode,
721                                    but the function will catch that. */
722                                ipc_to_master( cmd );
723                        }
724                        else
725                        {
726                                irc_commands[i].execute( irc, cmd );
727                        }
728                       
729                        return;
730                }
731       
732        if( irc->status >= USTATUS_LOGGED_IN )
733                irc_send_num( irc, 421, "%s :Unknown command", cmd[0] );
734}
Note: See TracBrowser for help on using the repository browser.