source: irc_commands.c @ 191cfb1

Last change on this file since 191cfb1 was bedad20, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-11-24T22:32:12Z

Some polishing/documentation for the "account add" without password hack.

  • Property mode set to 100644
File size: 20.2 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"
[674a01d]28#include "help.h"
[0431ea1]29#include "ipc.h"
[0298d11]30
[f73b969]31static void irc_cmd_pass( irc_t *irc, char **cmd )
[0298d11]32{
[a199d33]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. */
[daae10f]41                root_command( irc, send_cmd );
42                return;
[a199d33]43        }
44        /* Handling in pre-logged-in state, first see if this server is
45           password-protected: */
46        else if( global.conf->auth_pass &&
[c029350]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 ) )
[0298d11]50        {
[79e826a]51                irc->status |= USTATUS_AUTHORIZED;
[de3e100]52                irc_check_login( irc );
[0298d11]53        }
[a199d33]54        else if( global.conf->auth_pass )
[0298d11]55        {
[3ddb7477]56                irc_send_num( irc, 464, ":Incorrect password" );
[0298d11]57        }
[a199d33]58        else
59        {
60                /* Remember the password and try to identify after USER/NICK. */
[70f69ecc]61                irc_setpass( irc, cmd[1] );
[a199d33]62                irc_check_login( irc );
63        }
[0298d11]64}
65
[f73b969]66static void irc_cmd_user( irc_t *irc, char **cmd )
[0298d11]67{
[3ddb7477]68        irc->user->user = g_strdup( cmd[1] );
69        irc->user->fullname = g_strdup( cmd[4] );
[edf9657]70       
71        irc_check_login( irc );
[0298d11]72}
73
[f73b969]74static void irc_cmd_nick( irc_t *irc, char **cmd )
[0298d11]75{
[9a9b520]76        irc_user_t *iu;
77       
78        if( ( iu = irc_user_by_name( irc, cmd[1] ) ) && iu != irc->user )
[0298d11]79        {
[9a9b520]80                irc_send_num( irc, 433, "%s :This nick is already in use", cmd[1] );
[0298d11]81        }
82        else if( !nick_ok( cmd[1] ) )
83        {
84                /* [SH] Invalid characters. */
[9a9b520]85                irc_send_num( irc, 432, "%s :This nick contains invalid characters", cmd[1] );
[0298d11]86        }
[9a9b520]87        else if( irc->status & USTATUS_LOGGED_IN )
[ffa1173]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 );
[92cb8c4]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." );
[ffa1173]98                }
99               
100                irc_user_set_nick( irc->user, cmd[1] );
101        }
[0298d11]102        else
103        {
[9a9b520]104                g_free( irc->user->nick );
[3ddb7477]105                irc->user->nick = g_strdup( cmd[1] );
[edf9657]106               
107                irc_check_login( irc );
[0298d11]108        }
109}
110
[f73b969]111static void irc_cmd_quit( irc_t *irc, char **cmd )
[0298d11]112{
[f73b969]113        if( cmd[1] && *cmd[1] )
114                irc_abort( irc, 0, "Quit: %s", cmd[1] );
115        else
116                irc_abort( irc, 0, "Leaving..." );
[0298d11]117}
118
[f73b969]119static void irc_cmd_ping( irc_t *irc, char **cmd )
[0298d11]120{
[ebaebfe]121        irc_write( irc, ":%s PONG %s :%s", irc->root->host,
122                   irc->root->host, cmd[1]?cmd[1]:irc->root->host );
[0298d11]123}
124
[3923003]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
[b9e020a]133static void irc_cmd_join( irc_t *irc, char **cmd )
134{
[58646d9]135        char *comma, *s = cmd[1];
[b9e020a]136       
[58646d9]137        while( s )
[57119e8]138        {
[58646d9]139                irc_channel_t *ic;
140               
141                if( ( comma = strchr( s, ',' ) ) )
142                        *comma = '\0';
143               
[13fa2db]144                if( ( ic = irc_channel_by_name( irc, s ) ) == NULL &&
145                    ( ic = irc_channel_new( irc, s ) ) )
[324c378]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                        {
[13fa2db]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. */
[324c378]169                                bee_irc_channel_update( ic->irc, ic, NULL );
170                        }
171                }
[13fa2db]172                else if( ic == NULL )
[58646d9]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;
[57119e8]202        }
[b9e020a]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        }
[b1af3e8]231        else if( irc_channel_del_user( ic, irc->user, IRC_CDU_PART, cmd[2] ) )
[47fae0f]232        {
233                if( ic->f->part )
234                        ic->f->part( ic, NULL );
235        }
236        else
[b9e020a]237        {
238                irc_send_num( irc, 442, "%s :You're not on that channel", cmd[1] );
239        }
240}
241
[b95932e]242static void irc_cmd_whois( irc_t *irc, char **cmd )
243{
244        char *nick = cmd[1];
[280c56a]245        irc_user_t *iu = irc_user_by_name( irc, nick );
[b95932e]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
[9b69eb7]264static void irc_cmd_motd( irc_t *irc, char **cmd )
265{
266        irc_send_motd( irc );
267}
268
[f73b969]269static void irc_cmd_mode( irc_t *irc, char **cmd )
[0298d11]270{
[b919363]271        if( irc_channel_name_ok( cmd[1] ) )
[0298d11]272        {
[b919363]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] )
[0298d11]278                {
279                        if( *cmd[2] == '+' || *cmd[2] == '-' )
[3ddb7477]280                                irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] );
[0298d11]281                        else if( *cmd[2] == 'b' )
[3ddb7477]282                                irc_send_num( irc, 368, "%s :No bans possible", cmd[1] );
[0298d11]283                }
284                else
[b919363]285                        irc_send_num( irc, 324, "%s +%s", cmd[1], ic->mode );
[0298d11]286        }
287        else
288        {
[b919363]289                if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
[0298d11]290                {
291                        if( cmd[2] )
292                                irc_umode_set( irc, cmd[2], 0 );
[2f13222]293                        else
[3ddb7477]294                                irc_send_num( irc, 221, "+%s", irc->umode );
[0298d11]295                }
296                else
[3ddb7477]297                        irc_send_num( irc, 502, ":Don't touch their modes" );
[0298d11]298        }
299}
300
[2f53ada]301static void irc_cmd_who( irc_t *irc, char **cmd )
302{
303        char *channel = cmd[1];
304        irc_channel_t *ic;
[a72af0d]305        irc_user_t *iu;
[2f53ada]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 );
[a72af0d]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        }
[2f53ada]318        else
319                irc_send_num( irc, 403, "%s :No such channel", channel );
320}
321
[280c56a]322static void irc_cmd_privmsg( irc_t *irc, char **cmd )
[b919363]323{
[280c56a]324        irc_channel_t *ic;
325        irc_user_t *iu;
326       
327        if( !cmd[2] ) 
[b919363]328        {
[280c56a]329                irc_send_num( irc, 412, ":No text to send" );
[24b8bbb]330                return;
[280c56a]331        }
[24b8bbb]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;
[e1f3f94]337                memcpy( cmd[2], "/me", 3 );
[24b8bbb]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] ) ) )
[280c56a]344        {
[a7dbf45]345                if( cmd[2][0] == '\001' )
346                {
347                        /* CTCPs to channels? Nah. Maybe later. */
348                }
349                else if( ic->f->privmsg )
[280c56a]350                        ic->f->privmsg( ic, cmd[2] );
351        }
352        else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) )
353        {
[24b8bbb]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 )
[bce78c8]367                {
[92c8d41]368                        iu->last_channel = NULL;
[280c56a]369                        iu->f->privmsg( iu, cmd[2] );
[bce78c8]370                }
[b919363]371        }
372        else
373        {
[280c56a]374                irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] );
[b919363]375        }
[280c56a]376}
377
[d7f8500]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
[d860a8d]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
[280c56a]399
400
401static void irc_cmd_oper( irc_t *irc, char **cmd )
402{
[9564e55]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] );
[bedad20]411                        irc_usermsg( irc, "Password added to IM account "
412                                     "%s(%s)", a->prpl->name, a->user );
413                        /* The IRC client may expect this. Report failure since
414                           we didn't hand out a +o. */
415                        irc_send_num( irc, 491, ":Password added to IM account "
416                                      "%s(%s)", a->prpl->name, a->user );
[9564e55]417                        return;
418                }
419       
[280c56a]420        if( global.conf->oper_pass &&
421            ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
422                md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
423                strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
424        {
425                irc_umode_set( irc, "+o", 1 );
426                irc_send_num( irc, 381, ":Password accepted" );
427        }
428        else
429        {
[bedad20]430                irc_send_num( irc, 491, ":Incorrect password" );
[280c56a]431        }
432}
433
434static void irc_cmd_invite( irc_t *irc, char **cmd )
435{
[66b9e36a]436        irc_channel_t *ic;
437        irc_user_t *iu;
[280c56a]438       
[66b9e36a]439        if( ( iu = irc_user_by_name( irc, cmd[1] ) ) == NULL )
440        {
441                irc_send_num( irc, 401, "%s :No such nick", cmd[1] );
442                return;
443        }
444        else if( ( ic = irc_channel_by_name( irc, cmd[2] ) ) == NULL )
445        {
446                irc_send_num( irc, 403, "%s :No such channel", cmd[2] );
447                return;
448        }
[280c56a]449       
[46d215d]450        if( !ic->f->invite )
[66b9e36a]451                irc_send_num( irc, 482, "%s :Can't invite people here", cmd[2] );
[46d215d]452        else if( ic->f->invite( ic, iu ) )
453                irc_send_num( irc, 341, "%s %s", iu->nick, ic->name );
[0298d11]454}
455
[f73b969]456static void irc_cmd_userhost( irc_t *irc, char **cmd )
[0298d11]457{
458        int i;
459       
460        /* [TV] Usable USERHOST-implementation according to
461                RFC1459. Without this, mIRC shows an error
462                while connecting, and the used way of rejecting
463                breaks standards.
464        */
465       
466        for( i = 1; cmd[i]; i ++ )
[003a12b]467        {
468                irc_user_t *iu = irc_user_by_name( irc, cmd[i] );
469               
470                if( iu )
471                        irc_send_num( irc, 302, ":%s=%c%s@%s", iu->nick,
472                                      irc_user_get_away( iu ) ? '-' : '+',
473                                      iu->user, iu->host );
474        }
[0298d11]475}
476
[f73b969]477static void irc_cmd_ison( irc_t *irc, char **cmd )
[0298d11]478{
[b4e4b95]479        char buff[IRC_MAX_LINE];
[0298d11]480        int lenleft, i;
481       
482        buff[0] = '\0';
483       
484        /* [SH] Leave room for : and \0 */
485        lenleft = IRC_MAX_LINE - 2;
486       
487        for( i = 1; cmd[i]; i ++ )
488        {
[42616d1]489                char *this, *next;
490               
491                this = cmd[i];
492                while( *this )
[0298d11]493                {
[003a12b]494                        irc_user_t *iu;
495                       
[42616d1]496                        if( ( next = strchr( this, ' ' ) ) )
497                                *next = 0;
[0298d11]498                       
[003a12b]499                        if( ( iu = irc_user_by_name( irc, this ) ) &&
500                            iu->bu && iu->bu->flags & BEE_USER_ONLINE )
[0298d11]501                        {
[003a12b]502                                lenleft -= strlen( iu->nick ) + 1;
[42616d1]503                               
504                                if( lenleft < 0 )
505                                        break;
506                               
[003a12b]507                                strcat( buff, iu->nick );
[42616d1]508                                strcat( buff, " " );
[0298d11]509                        }
510                       
[42616d1]511                        if( next )
512                        {
513                                *next = ' ';
514                                this = next + 1;
515                        }
516                        else
517                        {
518                                break;
519                        }   
[0298d11]520                }
[42616d1]521               
522                /* *sigh* */
523                if( lenleft < 0 )
524                        break;
[0298d11]525        }
526       
527        if( strlen( buff ) > 0 )
528                buff[strlen(buff)-1] = '\0';
529       
[3ddb7477]530        irc_send_num( irc, 303, ":%s", buff );
[0298d11]531}
532
[f73b969]533static void irc_cmd_watch( irc_t *irc, char **cmd )
[0298d11]534{
535        int i;
536       
537        /* Obviously we could also mark a user structure as being
538           watched, but what if the WATCH command is sent right
539           after connecting? The user won't exist yet then... */
540        for( i = 1; cmd[i]; i ++ )
541        {
542                char *nick;
[003a12b]543                irc_user_t *iu;
[0298d11]544               
545                if( !cmd[i][0] || !cmd[i][1] )
546                        break;
547               
548                nick = g_strdup( cmd[i] + 1 );
549                nick_lc( nick );
550               
[003a12b]551                iu = irc_user_by_name( irc, nick );
[0298d11]552               
553                if( cmd[i][0] == '+' )
554                {
555                        if( !g_hash_table_lookup( irc->watches, nick ) )
556                                g_hash_table_insert( irc->watches, nick, nick );
557                       
[003a12b]558                        if( iu && iu->bu && iu->bu->flags & BEE_USER_ONLINE )
559                                irc_send_num( irc, 604, "%s %s %s %d :%s", iu->nick, iu->user,
560                                              iu->host, (int) time( NULL ), "is online" );
[0298d11]561                        else
[003a12b]562                                irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*",
563                                              (int) time( NULL ), "is offline" );
[0298d11]564                }
565                else if( cmd[i][0] == '-' )
566                {
567                        gpointer okey, ovalue;
568                       
569                        if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
570                        {
571                                g_hash_table_remove( irc->watches, okey );
[e59b4f6]572                                g_free( okey );
[0298d11]573                               
[3ddb7477]574                                irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
[0298d11]575                        }
576                }
577        }
578}
579
[f73b969]580static void irc_cmd_topic( irc_t *irc, char **cmd )
[0298d11]581{
[4469e7e]582        irc_channel_t *ic = irc_channel_by_name( irc, cmd[1] );
583        const char *new = cmd[2];
[50e1776]584       
[4469e7e]585        if( ic == NULL )
[50e1776]586        {
[4469e7e]587                irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
588        }
589        else if( new )
590        {
591                if( ic->f->topic == NULL )
592                        irc_send_num( irc, 482, "%s :Can't change this channel's topic", ic->name );
593                else if( ic->f->topic( ic, new ) )
594                        irc_send_topic( ic, TRUE );
[50e1776]595        }
[0298d11]596        else
[50e1776]597        {
[4469e7e]598                irc_send_topic( ic, FALSE );
[50e1776]599        }
[0298d11]600}
601
[f73b969]602static void irc_cmd_away( irc_t *irc, char **cmd )
[0298d11]603{
[81186cab]604        if( cmd[1] && *cmd[1] )
[0298d11]605        {
[81186cab]606                char away[strlen(cmd[1])+1];
[0298d11]607                int i, j;
608               
609                /* Copy away string, but skip control chars. Mainly because
610                   Jabber really doesn't like them. */
[81186cab]611                for( i = j = 0; cmd[1][i]; i ++ )
612                        if( ( away[j] = cmd[1][i] ) >= ' ' )
[0298d11]613                                j ++;
[81186cab]614                away[j] = '\0';
[0298d11]615               
[81186cab]616                irc_send_num( irc, 306, ":You're now away: %s", away );
[4a9fd5f]617                set_setstr( &irc->b->set, "away", away );
[0298d11]618        }
619        else
620        {
[3ddb7477]621                irc_send_num( irc, 305, ":Welcome back" );
[4a9fd5f]622                set_setstr( &irc->b->set, "away", NULL );
[0298d11]623        }
624}
625
[23d6165]626static void irc_cmd_list( irc_t *irc, char **cmd )
627{
628        GSList *l;
629       
630        for( l = irc->channels; l; l = l->next )
631        {
632                irc_channel_t *ic = l->data;
633               
634                irc_send_num( irc, 322, "%s %d :%s",
635                              ic->name, g_slist_length( ic->users ), ic->topic ? : "" );
636        }
637        irc_send_num( irc, 323, ":%s", "End of /LIST" );
638}
639
[82898af]640static void irc_cmd_version( irc_t *irc, char **cmd )
641{
[d7d677d]642        irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ",
643                      BITLBEE_VERSION, irc->root->host, ARCH, CPU );
[82898af]644}
645
[f73b969]646static void irc_cmd_completions( irc_t *irc, char **cmd )
[0298d11]647{
648        help_t *h;
649        set_t *s;
650        int i;
651       
[d7d677d]652        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS OK" );
[0298d11]653       
[8358691]654        for( i = 0; root_commands[i].command; i ++ )
655                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS %s", root_commands[i].command );
[0298d11]656       
657        for( h = global.help; h; h = h->next )
[d7d677d]658                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS help %s", h->title );
[0298d11]659       
[d7d677d]660        for( s = irc->b->set; s; s = s->next )
661                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS set %s", s->key );
[0298d11]662       
[d7d677d]663        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS END" );
[0298d11]664}
665
[f73b969]666static void irc_cmd_rehash( irc_t *irc, char **cmd )
[f4a5940]667{
[5424c76]668        if( global.conf->runmode == RUNMODE_INETD )
669                ipc_master_cmd_rehash( NULL, NULL );
670        else
671                ipc_to_master( cmd );
[f4a5940]672       
[3ddb7477]673        irc_send_num( irc, 382, "%s :Rehashing", global.conf_file );
[f4a5940]674}
675
[0298d11]676static const command_t irc_commands[] = {
[a199d33]677        { "pass",        1, irc_cmd_pass,        0 },
[0298d11]678        { "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
679        { "nick",        1, irc_cmd_nick,        0 },
680        { "quit",        0, irc_cmd_quit,        0 },
681        { "ping",        0, irc_cmd_ping,        0 },
[3923003]682        { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
[b9e020a]683        { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
684        { "names",       1, irc_cmd_names,       IRC_CMD_LOGGED_IN },
685        { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
[b95932e]686        { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
687        { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
[9b69eb7]688        { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
[b919363]689        { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
[2f53ada]690        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
[280c56a]691        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
[d7f8500]692        { "notice",      1, irc_cmd_notice,      IRC_CMD_LOGGED_IN },
[d860a8d]693        { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
694        { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
[81186cab]695        { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
[d7d677d]696        { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
697        { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
[0298d11]698        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
699        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
700        { "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
[003a12b]701        { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
[4469e7e]702        { "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
[003a12b]703        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
[23d6165]704        { "list",        0, irc_cmd_list,        IRC_CMD_LOGGED_IN },
[0431ea1]705        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[565a1ea]706        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[48721c3]707        { "wallops",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[dfc8a46]708        { "wall",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[f4a5940]709        { "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY },
[54879ab]710        { "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[48721c3]711        { "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[0298d11]712        { NULL }
713};
714
[f73b969]715void irc_exec( irc_t *irc, char *cmd[] )
[0298d11]716{       
[f1d38f2]717        int i, n_arg;
[0298d11]718       
719        if( !cmd[0] )
[f73b969]720                return;
[0298d11]721       
722        for( i = 0; irc_commands[i].command; i++ )
723                if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 )
724                {
[f1d38f2]725                        /* There should be no typo in the next line: */
726                        for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --;
727                       
[79e826a]728                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
[edf9657]729                        {
[3ddb7477]730                                irc_send_num( irc, 462, ":Only allowed before logging in" );
[edf9657]731                        }
[3af70b0]732                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
[edf9657]733                        {
[3ddb7477]734                                irc_send_num( irc, 451, ":Register first" );
[edf9657]735                        }
[f73b969]736                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
[edf9657]737                        {
[3ddb7477]738                                irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" );
[edf9657]739                        }
[f1d38f2]740                        else if( n_arg < irc_commands[i].required_parameters )
[f73b969]741                        {
[3ddb7477]742                                irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] );
[f73b969]743                        }
744                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
745                        {
[5424c76]746                                /* IPC doesn't make sense in inetd mode,
747                                    but the function will catch that. */
[0431ea1]748                                ipc_to_master( cmd );
[f73b969]749                        }
[0431ea1]750                        else
[f73b969]751                        {
752                                irc_commands[i].execute( irc, cmd );
753                        }
754                       
[2f13222]755                        return;
[0298d11]756                }
[2f13222]757       
758        if( irc->status >= USTATUS_LOGGED_IN )
[3ddb7477]759                irc_send_num( irc, 421, "%s :Unknown command", cmd[0] );
[0298d11]760}
Note: See TracBrowser for help on using the repository browser.