source: irc_commands.c @ d7f8500

Last change on this file since d7f8500 was d7f8500, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-06-30T23:01:33Z

Support /NOTICE, although for now just to yourself - some IRC clients use
this to measure lag.

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