source: irc_im.c @ 7a6ba50

Last change on this file since 7a6ba50 was 7a6ba50, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-06-29T23:44:17Z

Also allow selecting contacts for a channel by protocol instead of account.
If someone has two MSN accts and wants contacts from both in one channel,
this is now possible.

  • Property mode set to 100644
File size: 20.4 KB
RevLine 
[81e04e1]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* Some glue to put the IRC and the IM stuff together.                  */
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#include "bitlbee.h"
[17a6ee9]27#include "dcc.h"
[d860a8d]28
[e4816ea]29/* IM->IRC callbacks: Simple IM/buddy-related stuff. */
[d860a8d]30
[81e04e1]31static const struct irc_user_funcs irc_user_im_funcs;
32
33static gboolean bee_irc_user_new( bee_t *bee, bee_user_t *bu )
34{
35        irc_user_t *iu;
[92c8d41]36        irc_t *irc = (irc_t*) bee->ui_data;
[81e04e1]37        char nick[MAX_NICK_LENGTH+1], *s;
38       
39        memset( nick, 0, MAX_NICK_LENGTH + 1 );
40        strcpy( nick, nick_get( bu->ic->acc, bu->handle ) );
41       
[92c8d41]42        bu->ui_data = iu = irc_user_new( irc, nick );
[d860a8d]43        iu->bu = bu;
[81e04e1]44       
45        if( ( s = strchr( bu->handle, '@' ) ) )
46        {
47                iu->host = g_strdup( s + 1 );
48                iu->user = g_strndup( bu->handle, s - bu->handle );
49        }
50        else if( bu->ic->acc->server )
51        {
52                iu->host = g_strdup( bu->ic->acc->server );
53                iu->user = g_strdup( bu->handle );
54               
55                /* s/ /_/ ... important for AOL screennames */
56                for( s = iu->user; *s; s ++ )
57                        if( *s == ' ' )
58                                *s = '_';
59        }
60        else
61        {
62                iu->host = g_strdup( bu->ic->acc->prpl->name );
63                iu->user = g_strdup( bu->handle );
64        }
65       
[ad404ab]66        if( bu->flags & BEE_USER_LOCAL )
67        {
68                char *s = set_getstr( &bee->set, "handle_unknown" );
69               
70                if( strcmp( s, "add_private" ) == 0 )
[92c8d41]71                        iu->last_channel = NULL;
[ad404ab]72                else if( strcmp( s, "add_channel" ) == 0 )
[92c8d41]73                        iu->last_channel = irc->default_channel;
[ad404ab]74        }
75       
[81e04e1]76        iu->f = &irc_user_im_funcs;
77       
78        return TRUE;
79}
80
[d860a8d]81static gboolean bee_irc_user_free( bee_t *bee, bee_user_t *bu )
82{
[eabc9d2]83        return irc_user_free( bee->ui_data, (irc_user_t *) bu->ui_data );
[d860a8d]84}
[81e04e1]85
[d860a8d]86static gboolean bee_irc_user_status( bee_t *bee, bee_user_t *bu, bee_user_t *old )
87{
[231b08b]88        irc_t *irc = bee->ui_data;
[003a12b]89        irc_user_t *iu = bu->ui_data;
[231b08b]90       
[eb50495]91        /* Do this outside the if below since away state can change without
92           the online state changing. */
93        iu->flags &= ~IRC_USER_AWAY;
94        if( bu->flags & BEE_USER_AWAY || !( bu->flags & BEE_USER_ONLINE ) )
95                iu->flags |= IRC_USER_AWAY;
96       
[231b08b]97        if( ( bu->flags & BEE_USER_ONLINE ) != ( old->flags & BEE_USER_ONLINE ) )
98        {
99                if( bu->flags & BEE_USER_ONLINE )
[003a12b]100                {
101                        if( g_hash_table_lookup( irc->watches, iu->key ) )
102                                irc_send_num( irc, 600, "%s %s %s %d :%s", iu->nick, iu->user,
103                                              iu->host, (int) time( NULL ), "logged online" );
104                }
[231b08b]105                else
[003a12b]106                {
107                        if( g_hash_table_lookup( irc->watches, iu->key ) )
108                                irc_send_num( irc, 601, "%s %s %s %d :%s", iu->nick, iu->user,
109                                              iu->host, (int) time( NULL ), "logged offline" );
110                }
[231b08b]111        }
112       
[1c8e5f7]113        /* Reset this one since the info may have changed. */
114        iu->away_reply_timeout = 0;
115       
[13c1a9f]116        bee_irc_channel_update( irc, NULL, iu );
117       
[d860a8d]118        return TRUE;
119}
[81e04e1]120
[13c1a9f]121void bee_irc_channel_update( irc_t *irc, irc_channel_t *ic, irc_user_t *iu )
122{
123        struct irc_control_channel *icc;
124        GSList *l;
125        gboolean show;
126       
127        if( ic == NULL )
128        {
129                for( l = irc->channels; l; l = l->next )
130                {
131                        ic = l->data;
132                        /* TODO: Just add a type flag or so.. */
133                        if( ic->f == irc->default_channel->f )
134                                bee_irc_channel_update( irc, ic, iu );
135                }
136                return;
137        }
138        if( iu == NULL )
139        {
140                for( l = irc->users; l; l = l->next )
141                {
142                        iu = l->data;
143                        if( iu->bu )
144                                bee_irc_channel_update( irc, ic, l->data );
145                }
146                return;
147        }
148       
149        icc = ic->data;
150       
151        if( !( iu->bu->flags & BEE_USER_ONLINE ) )
152                show = FALSE;
153        else if( icc->type == IRC_CC_TYPE_DEFAULT )
154                show = TRUE;
155        else if( icc->type == IRC_CC_TYPE_GROUP )
156                show = iu->bu->group == icc->group;
[a067771]157        else if( icc->type == IRC_CC_TYPE_ACCOUNT )
158                show = iu->bu->ic->acc == icc->account;
[7a6ba50]159        else if( icc->type == IRC_CC_TYPE_PROTOCOL )
160                show = iu->bu->ic->acc->prpl == icc->protocol;
[13c1a9f]161       
162        if( !show )
163        {
[18da20b]164                irc_channel_del_user( ic, iu, FALSE, NULL );
[13c1a9f]165        }
166        else
167        {
168                irc_channel_add_user( ic, iu );
169               
170                if( set_getbool( &irc->b->set, "away_devoice" ) )
171                        irc_channel_user_set_mode( ic, iu, ( iu->bu->flags & BEE_USER_AWAY ) ?
172                                                   0 : IRC_CHANNEL_USER_VOICE );
[0e8b3e8]173                else
174                        irc_channel_user_set_mode( ic, iu, 0 );
[13c1a9f]175        }
176}
177
[f012a9f]178static gboolean bee_irc_user_msg( bee_t *bee, bee_user_t *bu, const char *msg, time_t sent_at )
179{
180        irc_t *irc = bee->ui_data;
181        irc_user_t *iu = (irc_user_t *) bu->ui_data;
182        char *dst, *prefix = NULL;
[21c87a7]183        char *wrapped, *ts = NULL;
184       
185        if( sent_at > 0 && set_getbool( &irc->b->set, "display_timestamps" ) )
186                ts = irc_format_timestamp( irc, sent_at );
[f012a9f]187       
[92c8d41]188        if( iu->last_channel )
[f012a9f]189        {
[92c8d41]190                dst = iu->last_channel->name;
191                prefix = g_strdup_printf( "%s%s%s", irc->user->nick, set_getstr( &bee->set, "to_char" ), ts ? : "" );
[f012a9f]192        }
193        else
194        {
[92c8d41]195                dst = irc->user->nick;
196                prefix = ts;
197                ts = NULL;
[f012a9f]198        }
199       
200        wrapped = word_wrap( msg, 425 );
201        irc_send_msg( iu, "PRIVMSG", dst, wrapped, prefix );
202       
203        g_free( wrapped );
204        g_free( prefix );
[21c87a7]205        g_free( ts );
[f012a9f]206       
207        return TRUE;
208}
209
[573dab0]210static gboolean bee_irc_user_typing( bee_t *bee, bee_user_t *bu, uint32_t flags )
211{
212        irc_t *irc = (irc_t *) bee->ui_data;
213       
214        if( set_getbool( &bee->set, "typing_notice" ) )
215                irc_send_msg_f( (irc_user_t *) bu->ui_data, "PRIVMSG", irc->user->nick,
216                                "\001TYPING %d\001", ( flags >> 8 ) & 3 );
217        else
218                return FALSE;
219       
220        return TRUE;
221}
222
[6ef9065]223static gboolean bee_irc_user_nick_hint( bee_t *bee, bee_user_t *bu, const char *hint );
224
[1d39159]225static gboolean bee_irc_user_fullname( bee_t *bee, bee_user_t *bu )
226{
227        irc_user_t *iu = (irc_user_t *) bu->ui_data;
228        irc_t *irc = (irc_t *) bee->ui_data;
229        char *s;
230       
231        if( iu->fullname != iu->nick )
232                g_free( iu->fullname );
233        iu->fullname = g_strdup( bu->fullname );
234       
235        /* Strip newlines (unlikely, but IRC-unfriendly so they must go)
236           TODO(wilmer): Do the same with away msgs again! */
237        for( s = iu->fullname; *s; s ++ )
238                if( isspace( *s ) ) *s = ' ';
239       
240        if( ( bu->ic->flags & OPT_LOGGED_IN ) && set_getbool( &bee->set, "display_namechanges" ) )
241        {
242                char *msg = g_strdup_printf( "<< \002BitlBee\002 - Changed name to `%s' >>", iu->fullname );
243                irc_send_msg( iu, "NOTICE", irc->user->nick, msg, NULL );
244        }
245       
246        s = set_getstr( &bu->ic->acc->set, "nick_source" );
247        if( strcmp( s, "handle" ) != 0 )
248        {
249                char *name = g_strdup( bu->fullname );
250               
251                if( strcmp( s, "first_name" ) == 0 )
252                {
253                        int i;
254                        for( i = 0; name[i] && !isspace( name[i] ); i ++ ) {}
255                        name[i] = '\0';
256                }
257               
[6ef9065]258                bee_irc_user_nick_hint( bee, bu, name );
[1d39159]259               
260                g_free( name );
261        }
262       
263        return TRUE;
264}
265
[6ef9065]266static gboolean bee_irc_user_nick_hint( bee_t *bee, bee_user_t *bu, const char *hint )
267{
268        irc_user_t *iu = bu->ui_data;
269        char newnick[MAX_NICK_LENGTH+1], *translit;
270       
271        if( bu->flags & BEE_USER_ONLINE )
272                /* Ignore if the user is visible already. */
273                return TRUE;
274       
275        if( nick_saved( bu->ic->acc, bu->handle ) )
276                /* The user already assigned a nickname to this person. */
277                return TRUE;
278       
279        /* Credits to Josay_ in #bitlbee for this idea. //TRANSLIT should
280           do lossy/approximate conversions, so letters with accents don't
281           just get stripped. Note that it depends on LC_CTYPE being set to
282           something other than C/POSIX. */
283        translit = g_convert( hint, -1, "ASCII//TRANSLIT//IGNORE", "UTF-8",
284                              NULL, NULL, NULL );
285       
286        strncpy( newnick, translit ? : hint, MAX_NICK_LENGTH );
287        newnick[MAX_NICK_LENGTH] = 0;
288        g_free( translit );
289       
290        /* Some processing to make sure this string is a valid IRC nickname. */
291        nick_strip( newnick );
292        if( set_getbool( &bee->set, "lcnicks" ) )
293                nick_lc( newnick );
294       
295        if( strcmp( iu->nick, newnick ) != 0 )
296        {
297                /* Only do this if newnick is different from the current one.
298                   If rejoining a channel, maybe we got this nick already
299                   (and dedupe would only add an underscore. */
300                nick_dedupe( bu->ic->acc, bu->handle, newnick );
301                irc_user_set_nick( iu, newnick );
302        }
303       
304        return TRUE;
305}
306
[7e83e8e4]307static gboolean bee_irc_user_group( bee_t *bee, bee_user_t *bu )
308{
309        irc_user_t *iu = (irc_user_t *) bu->ui_data;
310        irc_t *irc = (irc_t *) bee->ui_data;
311       
312        bee_irc_channel_update( irc, NULL, iu );
313       
314        return TRUE;
315}
316
[e4816ea]317/* IRC->IM calls */
318
[619dd18]319static gboolean bee_irc_user_privmsg_cb( gpointer data, gint fd, b_input_condition cond );
320
[e4816ea]321static gboolean bee_irc_user_privmsg( irc_user_t *iu, const char *msg )
322{
[1c8e5f7]323        const char *away;
324       
[619dd18]325        if( iu->bu == NULL )
[e4816ea]326                return FALSE;
[1c8e5f7]327       
328        if( ( away = irc_user_get_away( iu ) ) &&
329            time( NULL ) >= iu->away_reply_timeout )
330        {
331                irc_send_num( iu->irc, 301, "%s :%s", iu->nick, away );
332                iu->away_reply_timeout = time( NULL ) +
333                        set_getint( &iu->irc->b->set, "away_reply_timeout" );
334        }
335       
336        if( set_getbool( &iu->irc->b->set, "paste_buffer" ) )
[619dd18]337        {
338                int delay;
339               
340                if( iu->pastebuf == NULL )
341                        iu->pastebuf = g_string_new( msg );
342                else
343                {
344                        b_event_remove( iu->pastebuf_timer );
345                        g_string_append_printf( iu->pastebuf, "\n%s", msg );
346                }
347               
348                if( ( delay = set_getint( &iu->irc->b->set, "paste_buffer_delay" ) ) <= 5 )
349                        delay *= 1000;
350               
351                iu->pastebuf_timer = b_timeout_add( delay, bee_irc_user_privmsg_cb, iu );
352               
353                return TRUE;
354        }
355        else
356                return bee_user_msg( iu->irc->b, iu->bu, msg, 0 );
357}
358
359static gboolean bee_irc_user_privmsg_cb( gpointer data, gint fd, b_input_condition cond )
360{
361        irc_user_t *iu = data;
362       
363        bee_user_msg( iu->irc->b, iu->bu, iu->pastebuf->str, 0 );
364       
365        g_string_free( iu->pastebuf, TRUE );
366        iu->pastebuf = 0;
367        iu->pastebuf_timer = 0;
368       
369        return FALSE;
[e4816ea]370}
371
372static gboolean bee_irc_user_ctcp( irc_user_t *iu, char *const *ctcp )
373{
374        if( ctcp[1] && g_strcasecmp( ctcp[0], "DCC" ) == 0
375                    && g_strcasecmp( ctcp[1], "SEND" ) == 0 )
376        {
377                if( iu->bu && iu->bu->ic && iu->bu->ic->acc->prpl->transfer_request )
378                {
379                        file_transfer_t *ft = dcc_request( iu->bu->ic, ctcp );
380                        if ( ft )
381                                iu->bu->ic->acc->prpl->transfer_request( iu->bu->ic, ft, iu->bu->handle );
382                       
383                        return TRUE;
384                }
385        }
386        else if( g_strcasecmp( ctcp[0], "TYPING" ) == 0 )
387        {
388                if( iu->bu && iu->bu->ic && iu->bu->ic->acc->prpl->send_typing && ctcp[1] )
389                {
390                        int st = ctcp[1][0];
391                        if( st >= '0' && st <= '2' )
392                        {
393                                st <<= 8;
394                                iu->bu->ic->acc->prpl->send_typing( iu->bu->ic, iu->bu->handle, st );
395                        }
396                       
397                        return TRUE;
398                }
399        }
400       
401        return FALSE;
402}
403
404static const struct irc_user_funcs irc_user_im_funcs = {
405        bee_irc_user_privmsg,
406        bee_irc_user_ctcp,
407};
408
[aea8b68]409
[e4816ea]410/* IM->IRC: Groupchats */
[5a75d15]411const struct irc_channel_funcs irc_channel_im_chat_funcs;
[a87754b]412
413static gboolean bee_irc_chat_new( bee_t *bee, struct groupchat *c )
[aea8b68]414{
415        irc_t *irc = bee->ui_data;
416        irc_channel_t *ic;
417        char *topic;
[eb37735]418        GSList *l;
[aea8b68]419        int i;
420       
[eb37735]421        /* Try to find a channel that expects to receive a groupchat.
422           This flag is set by groupchat_stub_invite(). */
423        for( l = irc->channels; l; l = l->next )
424        {
425                ic = l->data;
426                if( ic->flags & IRC_CHANNEL_CHAT_PICKME )
427                        break;
428        }
429       
430        /* If we found none, just generate some stupid name. */
431        if( l == NULL ) for( i = 0; i <= 999; i ++ )
[aea8b68]432        {
433                char name[16];
[5a75d15]434                sprintf( name, "#chat_%03d", i );
[aea8b68]435                if( ( ic = irc_channel_new( irc, name ) ) )
436                        break;
437        }
438       
439        if( ic == NULL )
440                return FALSE;
441       
442        c->ui_data = ic;
443        ic->data = c;
444       
445        topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title );
446        irc_channel_set_topic( ic, topic, irc->root );
447        g_free( topic );
448       
449        return TRUE;
450}
451
[a87754b]452static gboolean bee_irc_chat_free( bee_t *bee, struct groupchat *c )
[aea8b68]453{
454        irc_channel_t *ic = c->ui_data;
455       
456        if( ic->flags & IRC_CHANNEL_JOINED )
457                irc_channel_printf( ic, "Cleaning up channel, bye!" );
458       
[5a75d15]459        ic->data = NULL;
[1c40aa7]460        irc_channel_del_user( ic, ic->irc->user, FALSE, "Chatroom closed by server" );
[aea8b68]461       
462        return TRUE;
463}
464
[a87754b]465static gboolean bee_irc_chat_log( bee_t *bee, struct groupchat *c, const char *text )
[aea8b68]466{
[27e2c66]467        irc_channel_t *ic = c->ui_data;
468       
469        irc_channel_printf( ic, "%s", text );
[b17ce85]470       
471        return TRUE;
[aea8b68]472}
473
[a87754b]474static gboolean bee_irc_chat_msg( bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, time_t sent_at )
[aea8b68]475{
[27e2c66]476        irc_t *irc = bee->ui_data;
477        irc_user_t *iu = bu->ui_data;
478        irc_channel_t *ic = c->ui_data;
479        char *ts = NULL;
480       
481        if( sent_at > 0 && set_getbool( &bee->set, "display_timestamps" ) )
482                ts = irc_format_timestamp( irc, sent_at );
483       
484        irc_send_msg( iu, "PRIVMSG", ic->name, msg, ts );
485        g_free( ts );
486       
487        return TRUE;
[aea8b68]488}
489
[a87754b]490static gboolean bee_irc_chat_add_user( bee_t *bee, struct groupchat *c, bee_user_t *bu )
[aea8b68]491{
492        irc_t *irc = bee->ui_data;
493       
494        irc_channel_add_user( c->ui_data, bu == bee->user ? irc->user : bu->ui_data );
[b17ce85]495       
496        return TRUE;
[aea8b68]497}
498
[a87754b]499static gboolean bee_irc_chat_remove_user( bee_t *bee, struct groupchat *c, bee_user_t *bu )
[aea8b68]500{
[b17ce85]501        irc_t *irc = bee->ui_data;
502       
[1c40aa7]503        /* TODO: Possible bug here: If a module removes $user here instead of just
504           using imcb_chat_free() and the channel was IRC_CHANNEL_TEMP, we get into
505           a broken state around here. */
[18da20b]506        irc_channel_del_user( c->ui_data, bu == bee->user ? irc->user : bu->ui_data, FALSE, NULL );
[b17ce85]507       
508        return TRUE;
[aea8b68]509}
510
[9e27f18]511static gboolean bee_irc_chat_topic( bee_t *bee, struct groupchat *c, const char *new, bee_user_t *bu )
512{
513        irc_t *irc = bee->ui_data;
514        irc_user_t *iu;
515       
516        if( bu == NULL )
517                iu = irc->root;
518        else if( bu == bee->user )
519                iu = irc->user;
520        else
521                iu = bu->ui_data;
522       
523        irc_channel_set_topic( c->ui_data, new, iu );
524       
525        return TRUE;
526}
527
[d343eaa]528static gboolean bee_irc_chat_name_hint( bee_t *bee, struct groupchat *c, const char *name )
529{
530        irc_t *irc = bee->ui_data;
531        irc_channel_t *ic = c->ui_data;
532        char stripped[MAX_NICK_LENGTH+1], *full_name;
533       
534        /* Don't rename a channel if the user's in it already. */
535        if( ic->flags & IRC_CHANNEL_JOINED )
536                return FALSE;
537       
538        strncpy( stripped, name, MAX_NICK_LENGTH );
539        stripped[MAX_NICK_LENGTH] = '\0';
[134a02c]540        irc_channel_name_strip( stripped );
[d343eaa]541        if( set_getbool( &bee->set, "lcnicks" ) )
542                nick_lc( stripped );
543       
[134a02c]544        full_name = g_strdup_printf( "#%s", stripped );
[d343eaa]545       
546        if( stripped[0] && irc_channel_by_name( irc, full_name ) == NULL )
547        {
548                g_free( ic->name );
549                ic->name = full_name;
550        }
551        else
552        {
553                g_free( full_name );
554        }
555       
556        return TRUE;
557}
558
[a87754b]559/* IRC->IM */
[619dd18]560static gboolean bee_irc_channel_chat_privmsg_cb( gpointer data, gint fd, b_input_condition cond );
561
[a87754b]562static gboolean bee_irc_channel_chat_privmsg( irc_channel_t *ic, const char *msg )
563{
564        struct groupchat *c = ic->data;
565       
[5a75d15]566        if( c == NULL )
567                return FALSE;
[619dd18]568        else if( set_getbool( &ic->irc->b->set, "paste_buffer" ) )
569        {
570                int delay;
571               
572                if( ic->pastebuf == NULL )
573                        ic->pastebuf = g_string_new( msg );
574                else
575                {
576                        b_event_remove( ic->pastebuf_timer );
577                        g_string_append_printf( ic->pastebuf, "\n%s", msg );
578                }
579               
580                if( ( delay = set_getint( &ic->irc->b->set, "paste_buffer_delay" ) ) <= 5 )
581                        delay *= 1000;
582               
583                ic->pastebuf_timer = b_timeout_add( delay, bee_irc_channel_chat_privmsg_cb, ic );
584               
585                return TRUE;
586        }
587        else
588                bee_chat_msg( ic->irc->b, c, msg, 0 );
[a87754b]589       
590        return TRUE;
[5a75d15]591}
592
[619dd18]593static gboolean bee_irc_channel_chat_privmsg_cb( gpointer data, gint fd, b_input_condition cond )
594{
595        irc_channel_t *ic = data;
596       
597        bee_chat_msg( ic->irc->b, ic->data, ic->pastebuf->str, 0 );
598       
599        g_string_free( ic->pastebuf, TRUE );
600        ic->pastebuf = 0;
601        ic->pastebuf_timer = 0;
602       
603        return FALSE;
604}
605
[5a75d15]606static gboolean bee_irc_channel_chat_join( irc_channel_t *ic )
607{
608        char *acc_s, *room;
609        account_t *acc;
[a87754b]610       
[5a75d15]611        if( strcmp( set_getstr( &ic->set, "chat_type" ), "room" ) != 0 )
612                return TRUE;
613       
614        if( ( acc_s = set_getstr( &ic->set, "account" ) ) &&
615            ( room = set_getstr( &ic->set, "room" ) ) &&
616            ( acc = account_get( ic->irc->b, acc_s ) ) &&
617            acc->ic && acc->prpl->chat_join )
618        {
619                char *nick;
620               
621                if( !( nick = set_getstr( &ic->set, "nick" ) ) )
622                        nick = ic->irc->user->nick;
623               
624                ic->flags |= IRC_CHANNEL_CHAT_PICKME;
625                acc->prpl->chat_join( acc->ic, room, nick, NULL );
626                ic->flags &= ~IRC_CHANNEL_CHAT_PICKME;
627               
628                return FALSE;
629        }
630        else
631        {
632                irc_send_num( ic->irc, 403, "%s :Can't join channel, account offline?", ic->name );
633                return FALSE;
634        }
[a87754b]635}
636
[bfb99ee]637static gboolean bee_irc_channel_chat_part( irc_channel_t *ic, const char *msg )
638{
639        struct groupchat *c = ic->data;
640       
[5a75d15]641        if( c && c->ic->acc->prpl->chat_leave )
[bfb99ee]642                c->ic->acc->prpl->chat_leave( c );
643       
644        return TRUE;
645}
646
[9e27f18]647static gboolean bee_irc_channel_chat_topic( irc_channel_t *ic, const char *new )
648{
[4469e7e]649        struct groupchat *c = ic->data;
[5a75d15]650       
651        if( c == NULL )
652                return FALSE;
[4469e7e]653       
654        if( c->ic->acc->prpl->chat_topic == NULL )
655                irc_send_num( ic->irc, 482, "%s :IM network does not support channel topics", ic->name );
656        else
657        {
[5a75d15]658                /* TODO: Need more const goodness here, sigh */
659                char *topic = g_strdup( new );
[4469e7e]660                c->ic->acc->prpl->chat_topic( c, topic );
[5a75d15]661                g_free( topic );
[4469e7e]662                return TRUE;
663        }
664               
665        return FALSE;
[9e27f18]666}
667
[66b9e36a]668static gboolean bee_irc_channel_chat_invite( irc_channel_t *ic, irc_user_t *iu )
669{
670        struct groupchat *c = ic->data;
[5a75d15]671        bee_user_t *bu = iu->bu;
672       
673        if( bu == NULL )
674                return FALSE;
[66b9e36a]675       
[5a75d15]676        if( c )
677        {
678                if( iu->bu->ic != c->ic )
679                        irc_send_num( ic->irc, 482, "%s :Can't mix different IM networks in one groupchat", ic->name );
680                else if( c->ic->acc->prpl->chat_invite )
681                        c->ic->acc->prpl->chat_invite( c, iu->bu->handle, NULL );
682                else
683                        irc_send_num( ic->irc, 482, "%s :IM protocol does not support room invitations", ic->name );
684        }
685        else if( bu->ic->acc->prpl->chat_with &&
686                 strcmp( set_getstr( &ic->set, "chat_type" ), "groupchat" ) == 0 )
687        {
688                ic->flags |= IRC_CHANNEL_CHAT_PICKME;
689                iu->bu->ic->acc->prpl->chat_with( bu->ic, bu->handle );
690                ic->flags &= ~IRC_CHANNEL_CHAT_PICKME;
691        }
[66b9e36a]692        else
[5a75d15]693        {
[66b9e36a]694                irc_send_num( ic->irc, 482, "%s :IM protocol does not support room invitations", ic->name );
[5a75d15]695        }
[66b9e36a]696       
697        return TRUE;
698}
699
[5a75d15]700static char *set_eval_room_account( set_t *set, char *value );
[1c40aa7]701static char *set_eval_chat_type( set_t *set, char *value );
[5a75d15]702
703static gboolean bee_irc_channel_init( irc_channel_t *ic )
704{
705        set_add( &ic->set, "account", NULL, set_eval_room_account, ic );
[1c40aa7]706        set_add( &ic->set, "chat_type", "groupchat", set_eval_chat_type, ic );
[5a75d15]707        set_add( &ic->set, "nick", NULL, NULL, ic );
708        set_add( &ic->set, "room", NULL, NULL, ic );
709       
[1c40aa7]710        /* chat_type == groupchat */
711        ic->flags |= IRC_CHANNEL_TEMP;
712       
[5a75d15]713        return TRUE;
714}
715
716static char *set_eval_room_account( set_t *set, char *value )
717{
718        struct irc_channel *ic = set->data;
719        account_t *acc;
720       
721        if( !( acc = account_get( ic->irc->b, value ) ) )
722                return SET_INVALID;
723        else if( !acc->prpl->chat_join )
724        {
725                irc_usermsg( ic->irc, "Named chatrooms not supported on that account." );
726                return SET_INVALID;
727        }
728       
729        return g_strdup_printf( "%s(%s)", acc->prpl->name, acc->user );
730}
731
[1c40aa7]732static char *set_eval_chat_type( set_t *set, char *value )
733{
734        struct irc_channel *ic = set->data;
735       
736        if( strcmp( value, "groupchat" ) == 0 )
737                ic->flags |= IRC_CHANNEL_TEMP;
738        else if( strcmp( value, "room" ) == 0 )
739                ic->flags &= ~IRC_CHANNEL_TEMP;
740        else
741                return NULL;
742       
743        return value;
744}
745
[5a75d15]746static gboolean bee_irc_channel_free( irc_channel_t *ic )
747{
748        set_del( &ic->set, "account" );
749        set_del( &ic->set, "chat_type" );
750        set_del( &ic->set, "nick" );
751        set_del( &ic->set, "room" );
752       
[1c40aa7]753        ic->flags &= ~IRC_CHANNEL_TEMP;
754       
[5a75d15]755        return TRUE;
756}
757
758const struct irc_channel_funcs irc_channel_im_chat_funcs = {
[a87754b]759        bee_irc_channel_chat_privmsg,
[5a75d15]760        bee_irc_channel_chat_join,
[bfb99ee]761        bee_irc_channel_chat_part,
[9e27f18]762        bee_irc_channel_chat_topic,
[66b9e36a]763        bee_irc_channel_chat_invite,
[5a75d15]764
765        bee_irc_channel_init,
766        bee_irc_channel_free,
[a87754b]767};
768
[aea8b68]769
[e4816ea]770/* IM->IRC: File transfers */
[17a6ee9]771static file_transfer_t *bee_irc_ft_in_start( bee_t *bee, bee_user_t *bu, const char *file_name, size_t file_size )
772{
773        return dccs_send_start( bu->ic, (irc_user_t *) bu->ui_data, file_name, file_size );
774}
775
[a87754b]776static gboolean bee_irc_ft_out_start( struct im_connection *ic, file_transfer_t *ft )
[17a6ee9]777{
778        return dccs_recv_start( ft );
779}
780
[a87754b]781static void bee_irc_ft_close( struct im_connection *ic, file_transfer_t *ft )
[17a6ee9]782{
783        return dcc_close( ft );
784}
785
[a87754b]786static void bee_irc_ft_finished( struct im_connection *ic, file_transfer_t *file )
[17a6ee9]787{
788        dcc_file_transfer_t *df = file->priv;
789
790        if( file->bytes_transferred >= file->file_size )
791                dcc_finish( file );
792        else
793                df->proto_finished = TRUE;
794}
795
[d860a8d]796const struct bee_ui_funcs irc_ui_funcs = {
[81e04e1]797        bee_irc_user_new,
[d860a8d]798        bee_irc_user_free,
[1d39159]799        bee_irc_user_fullname,
[6ef9065]800        bee_irc_user_nick_hint,
[7e83e8e4]801        bee_irc_user_group,
[d860a8d]802        bee_irc_user_status,
[f012a9f]803        bee_irc_user_msg,
[573dab0]804        bee_irc_user_typing,
[17a6ee9]805       
[aea8b68]806        bee_irc_chat_new,
807        bee_irc_chat_free,
[27e2c66]808        bee_irc_chat_log,
809        bee_irc_chat_msg,
[aea8b68]810        bee_irc_chat_add_user,
[b17ce85]811        bee_irc_chat_remove_user,
[9e27f18]812        bee_irc_chat_topic,
[d343eaa]813        bee_irc_chat_name_hint,
[aea8b68]814       
[17a6ee9]815        bee_irc_ft_in_start,
816        bee_irc_ft_out_start,
817        bee_irc_ft_close,
818        bee_irc_ft_finished,
[81e04e1]819};
Note: See TracBrowser for help on using the repository browser.