1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
4 * Copyright 2002-2010 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* Some glue to put the IRC and the IM stuff together. */
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.
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.
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
29 /* IM->IRC callbacks: Simple IM/buddy-related stuff. */
31 static const struct irc_user_funcs irc_user_im_funcs
;
33 static void bee_irc_imc_connected( struct im_connection
*ic
)
35 irc_t
*irc
= (irc_t
*) ic
->bee
->ui_data
;
37 irc_channel_auto_joins( irc
, ic
->acc
);
40 static void bee_irc_imc_disconnected( struct im_connection
*ic
)
42 /* Maybe try to send /QUITs here instead of later on. */
45 static gboolean
bee_irc_user_new( bee_t
*bee
, bee_user_t
*bu
)
48 irc_t
*irc
= (irc_t
*) bee
->ui_data
;
49 char nick
[MAX_NICK_LENGTH
+1], *s
;
51 memset( nick
, 0, MAX_NICK_LENGTH
+ 1 );
52 strcpy( nick
, nick_get( bu
) );
54 bu
->ui_data
= iu
= irc_user_new( irc
, nick
);
57 if( set_getbool( &irc
->b
->set
, "private" ) )
58 iu
->last_channel
= NULL
;
60 iu
->last_channel
= irc_channel_with_user( irc
, iu
);
62 if( ( s
= strchr( bu
->handle
, '@' ) ) )
64 iu
->host
= g_strdup( s
+ 1 );
65 iu
->user
= g_strndup( bu
->handle
, s
- bu
->handle
);
69 iu
->user
= g_strdup( bu
->handle
);
70 if( bu
->ic
->acc
->server
)
71 iu
->host
= g_strdup( bu
->ic
->acc
->server
);
73 iu
->host
= g_strdup( bu
->ic
->acc
->prpl
->name
);
76 while( ( s
= strchr( iu
->user
, ' ' ) ) )
79 if( bu
->flags
& BEE_USER_LOCAL
)
81 char *s
= set_getstr( &bee
->set
, "handle_unknown" );
83 if( strcmp( s
, "add_private" ) == 0 )
84 iu
->last_channel
= NULL
;
85 else if( strcmp( s
, "add_channel" ) == 0 )
86 iu
->last_channel
= irc
->default_channel
;
89 iu
->f
= &irc_user_im_funcs
;
94 static gboolean
bee_irc_user_free( bee_t
*bee
, bee_user_t
*bu
)
96 return irc_user_free( bee
->ui_data
, (irc_user_t
*) bu
->ui_data
);
99 static gboolean
bee_irc_user_status( bee_t
*bee
, bee_user_t
*bu
, bee_user_t
*old
)
101 irc_t
*irc
= bee
->ui_data
;
102 irc_user_t
*iu
= bu
->ui_data
;
104 /* Do this outside the if below since away state can change without
105 the online state changing. */
106 iu
->flags
&= ~IRC_USER_AWAY
;
107 if( bu
->flags
& BEE_USER_AWAY
|| !( bu
->flags
& BEE_USER_ONLINE
) )
108 iu
->flags
|= IRC_USER_AWAY
;
110 if( ( bu
->flags
& BEE_USER_ONLINE
) != ( old
->flags
& BEE_USER_ONLINE
) )
112 if( bu
->flags
& BEE_USER_ONLINE
)
114 if( g_hash_table_lookup( irc
->watches
, iu
->key
) )
115 irc_send_num( irc
, 600, "%s %s %s %d :%s", iu
->nick
, iu
->user
,
116 iu
->host
, (int) time( NULL
), "logged online" );
120 if( g_hash_table_lookup( irc
->watches
, iu
->key
) )
121 irc_send_num( irc
, 601, "%s %s %s %d :%s", iu
->nick
, iu
->user
,
122 iu
->host
, (int) time( NULL
), "logged offline" );
124 /* Send a QUIT since those will also show up in any
125 query windows the user may have, plus it's only
126 one QUIT instead of possibly many (in case of
127 multiple control chans). If there's a channel that
128 shows offline people, a JOIN will follow. */
129 if( set_getbool( &bee
->set
, "offline_user_quits" ) )
130 irc_user_quit( iu
, "Leaving..." );
134 /* Reset this one since the info may have changed. */
135 iu
->away_reply_timeout
= 0;
137 bee_irc_channel_update( irc
, NULL
, iu
);
142 void bee_irc_channel_update( irc_t
*irc
, irc_channel_t
*ic
, irc_user_t
*iu
)
148 for( l
= irc
->channels
; l
; l
= l
->next
)
151 /* TODO: Just add a type flag or so.. */
152 if( ic
->f
== irc
->default_channel
->f
&&
153 ( ic
->flags
& IRC_CHANNEL_JOINED
) )
154 bee_irc_channel_update( irc
, ic
, iu
);
160 for( l
= irc
->users
; l
; l
= l
->next
)
164 bee_irc_channel_update( irc
, ic
, l
->data
);
169 if( !irc_channel_wants_user( ic
, iu
) )
171 irc_channel_del_user( ic
, iu
, IRC_CDU_PART
, NULL
);
175 struct irc_control_channel
*icc
= ic
->data
;
178 if( !( iu
->bu
->flags
& BEE_USER_ONLINE
) )
179 mode
= icc
->modes
[0];
180 else if( iu
->bu
->flags
& BEE_USER_AWAY
)
181 mode
= icc
->modes
[1];
183 mode
= icc
->modes
[2];
186 irc_channel_del_user( ic
, iu
, IRC_CDU_PART
, NULL
);
189 irc_channel_add_user( ic
, iu
);
190 irc_channel_user_set_mode( ic
, iu
, mode
);
195 static gboolean
bee_irc_user_msg( bee_t
*bee
, bee_user_t
*bu
, const char *msg_
, time_t sent_at
)
197 irc_t
*irc
= bee
->ui_data
;
198 irc_user_t
*iu
= (irc_user_t
*) bu
->ui_data
;
201 char *wrapped
, *ts
= NULL
;
202 char *msg
= g_strdup( msg_
);
205 if( sent_at
> 0 && set_getbool( &irc
->b
->set
, "display_timestamps" ) )
206 ts
= irc_format_timestamp( irc
, sent_at
);
208 dst
= irc_user_msgdest( iu
);
209 if( dst
!= irc
->user
->nick
)
211 /* if not messaging directly, call user by name */
212 prefix
= g_strdup_printf( "%s%s%s", irc
->user
->nick
, set_getstr( &bee
->set
, "to_char" ), ts
? : "" );
217 ts
= NULL
; /* don't double-free */
220 for( l
= irc_plugins
; l
; l
= l
->next
)
222 irc_plugin_t
*p
= l
->data
;
223 if( p
->filter_msg_in
)
225 char *s
= p
->filter_msg_in( iu
, msg
, 0 );
234 /* Modules can swallow messages. */
240 if( ( g_strcasecmp( set_getstr( &bee
->set
, "strip_html" ), "always" ) == 0 ) ||
241 ( ( bu
->ic
->flags
& OPT_DOES_HTML
) && set_getbool( &bee
->set
, "strip_html" ) ) )
243 char *s
= g_strdup( msg
);
249 wrapped
= word_wrap( msg
, 425 );
250 irc_send_msg( iu
, "PRIVMSG", dst
, wrapped
, prefix
);
260 static gboolean
bee_irc_user_typing( bee_t
*bee
, bee_user_t
*bu
, uint32_t flags
)
262 irc_t
*irc
= (irc_t
*) bee
->ui_data
;
264 if( set_getbool( &bee
->set
, "typing_notice" ) )
265 irc_send_msg_f( (irc_user_t
*) bu
->ui_data
, "PRIVMSG", irc
->user
->nick
,
266 "\001TYPING %d\001", ( flags
>> 8 ) & 3 );
273 static gboolean
bee_irc_user_action_response( bee_t
*bee
, bee_user_t
*bu
, const char *action
, char * const args
[], void *data
)
275 irc_t
*irc
= (irc_t
*) bee
->ui_data
;
276 GString
*msg
= g_string_new( "\001" );
278 g_string_append( msg
, action
);
281 if( strchr( *args
, ' ' ) )
282 g_string_append_printf( msg
, " \"%s\"", *args
);
284 g_string_append_printf( msg
, " %s", *args
);
287 g_string_append_c( msg
, '\001' );
289 irc_send_msg( (irc_user_t
*) bu
->ui_data
, "NOTICE", irc
->user
->nick
, msg
->str
, NULL
);
294 static gboolean
bee_irc_user_nick_update( irc_user_t
*iu
);
296 static gboolean
bee_irc_user_fullname( bee_t
*bee
, bee_user_t
*bu
)
298 irc_user_t
*iu
= (irc_user_t
*) bu
->ui_data
;
301 if( iu
->fullname
!= iu
->nick
)
302 g_free( iu
->fullname
);
303 iu
->fullname
= g_strdup( bu
->fullname
);
305 /* Strip newlines (unlikely, but IRC-unfriendly so they must go)
306 TODO(wilmer): Do the same with away msgs again! */
307 for( s
= iu
->fullname
; *s
; s
++ )
308 if( isspace( *s
) ) *s
= ' ';
310 if( ( bu
->ic
->flags
& OPT_LOGGED_IN
) && set_getbool( &bee
->set
, "display_namechanges" ) )
312 /* People don't like this /NOTICE. Meh, let's go back to the old one.
313 char *msg = g_strdup_printf( "<< \002BitlBee\002 - Changed name to `%s' >>", iu->fullname );
314 irc_send_msg( iu, "NOTICE", irc->user->nick, msg, NULL );
316 imcb_log( bu
->ic
, "User `%s' changed name to `%s'", iu
->nick
, iu
->fullname
);
319 bee_irc_user_nick_update( iu
);
324 static gboolean
bee_irc_user_nick_hint( bee_t
*bee
, bee_user_t
*bu
, const char *hint
)
326 bee_irc_user_nick_update( (irc_user_t
*) bu
->ui_data
);
331 static gboolean
bee_irc_user_group( bee_t
*bee
, bee_user_t
*bu
)
333 irc_user_t
*iu
= (irc_user_t
*) bu
->ui_data
;
334 irc_t
*irc
= (irc_t
*) bee
->ui_data
;
335 bee_user_flags_t online
;
337 /* Take the user offline temporarily so we can change the nick (if necessary). */
338 if( ( online
= bu
->flags
& BEE_USER_ONLINE
) )
339 bu
->flags
&= ~BEE_USER_ONLINE
;
341 bee_irc_channel_update( irc
, NULL
, iu
);
342 bee_irc_user_nick_update( iu
);
347 bee_irc_channel_update( irc
, NULL
, iu
);
353 static gboolean
bee_irc_user_nick_update( irc_user_t
*iu
)
355 bee_user_t
*bu
= iu
->bu
;
358 if( bu
->flags
& BEE_USER_ONLINE
)
359 /* Ignore if the user is visible already. */
362 if( nick_saved( bu
) )
363 /* The user already assigned a nickname to this person. */
366 newnick
= nick_get( bu
);
368 if( strcmp( iu
->nick
, newnick
) != 0 )
370 nick_dedupe( bu
, newnick
);
371 irc_user_set_nick( iu
, newnick
);
377 void bee_irc_user_nick_reset( irc_user_t
*iu
)
379 bee_user_t
*bu
= iu
->bu
;
380 bee_user_flags_t online
;
385 /* In this case, pretend the user is offline. */
386 if( ( online
= bu
->flags
& BEE_USER_ONLINE
) )
387 bu
->flags
&= ~BEE_USER_ONLINE
;
390 bee_irc_user_nick_update( iu
);
397 static gboolean
bee_irc_user_privmsg_cb( gpointer data
, gint fd
, b_input_condition cond
);
399 static gboolean
bee_irc_user_privmsg( irc_user_t
*iu
, const char *msg
)
406 if( ( away
= irc_user_get_away( iu
) ) &&
407 time( NULL
) >= iu
->away_reply_timeout
)
409 irc_send_num( iu
->irc
, 301, "%s :%s", iu
->nick
, away
);
410 iu
->away_reply_timeout
= time( NULL
) +
411 set_getint( &iu
->irc
->b
->set
, "away_reply_timeout" );
414 if( iu
->pastebuf
== NULL
)
415 iu
->pastebuf
= g_string_new( msg
);
418 b_event_remove( iu
->pastebuf_timer
);
419 g_string_append_printf( iu
->pastebuf
, "\n%s", msg
);
422 if( set_getbool( &iu
->irc
->b
->set
, "paste_buffer" ) )
426 if( ( delay
= set_getint( &iu
->irc
->b
->set
, "paste_buffer_delay" ) ) <= 5 )
429 iu
->pastebuf_timer
= b_timeout_add( delay
, bee_irc_user_privmsg_cb
, iu
);
435 bee_irc_user_privmsg_cb( iu
, 0, 0 );
441 static gboolean
bee_irc_user_privmsg_cb( gpointer data
, gint fd
, b_input_condition cond
)
443 irc_user_t
*iu
= data
;
447 msg
= g_string_free( iu
->pastebuf
, FALSE
);
449 iu
->pastebuf_timer
= 0;
451 for( l
= irc_plugins
; l
; l
= l
->next
)
453 irc_plugin_t
*p
= l
->data
;
454 if( p
->filter_msg_out
)
456 char *s
= p
->filter_msg_out( iu
, msg
, 0 );
465 /* Modules can swallow messages. */
473 bee_user_msg( iu
->irc
->b
, iu
->bu
, msg
, 0 );
480 static gboolean
bee_irc_user_ctcp( irc_user_t
*iu
, char *const *ctcp
)
482 if( ctcp
[1] && g_strcasecmp( ctcp
[0], "DCC" ) == 0
483 && g_strcasecmp( ctcp
[1], "SEND" ) == 0 )
485 if( iu
->bu
&& iu
->bu
->ic
&& iu
->bu
->ic
->acc
->prpl
->transfer_request
)
487 file_transfer_t
*ft
= dcc_request( iu
->bu
->ic
, ctcp
);
489 iu
->bu
->ic
->acc
->prpl
->transfer_request( iu
->bu
->ic
, ft
, iu
->bu
->handle
);
494 else if( g_strcasecmp( ctcp
[0], "TYPING" ) == 0 )
496 if( iu
->bu
&& iu
->bu
->ic
&& iu
->bu
->ic
->acc
->prpl
->send_typing
&& ctcp
[1] )
499 if( st
>= '0' && st
<= '2' )
502 iu
->bu
->ic
->acc
->prpl
->send_typing( iu
->bu
->ic
, iu
->bu
->handle
, st
);
508 else if( g_strcasecmp( ctcp
[0], "HELP" ) == 0 && iu
->bu
)
510 GString
*supp
= g_string_new( "Supported CTCPs:" );
513 if( iu
->bu
->ic
&& iu
->bu
->ic
->acc
->prpl
->transfer_request
)
514 g_string_append( supp
, " DCC SEND," );
515 if( iu
->bu
->ic
&& iu
->bu
->ic
->acc
->prpl
->send_typing
)
516 g_string_append( supp
, " TYPING," );
517 if( iu
->bu
->ic
->acc
->prpl
->buddy_action_list
)
518 for( l
= iu
->bu
->ic
->acc
->prpl
->buddy_action_list( iu
->bu
); l
; l
= l
->next
)
520 struct buddy_action
*ba
= l
->data
;
521 g_string_append_printf( supp
, " %s (%s),",
522 ba
->name
, ba
->description
);
524 g_string_truncate( supp
, supp
->len
- 1 );
525 irc_send_msg_f( iu
, "NOTICE", iu
->irc
->user
->nick
, "\001HELP %s\001", supp
->str
);
526 g_string_free( supp
, TRUE
);
528 else if( iu
->bu
&& iu
->bu
->ic
&& iu
->bu
->ic
->acc
->prpl
->buddy_action
)
530 iu
->bu
->ic
->acc
->prpl
->buddy_action( iu
->bu
, ctcp
[0], ctcp
+ 1, NULL
);
536 static const struct irc_user_funcs irc_user_im_funcs
= {
537 bee_irc_user_privmsg
,
542 /* IM->IRC: Groupchats */
543 const struct irc_channel_funcs irc_channel_im_chat_funcs
;
545 static gboolean
bee_irc_chat_new( bee_t
*bee
, struct groupchat
*c
)
547 irc_t
*irc
= bee
->ui_data
;
553 /* Try to find a channel that expects to receive a groupchat.
554 This flag is set earlier in our current call trace. */
555 for( l
= irc
->channels
; l
; l
= l
->next
)
558 if( ic
->flags
& IRC_CHANNEL_CHAT_PICKME
)
562 /* If we found none, just generate some stupid name. */
563 if( l
== NULL
) for( i
= 0; i
<= 999; i
++ )
566 sprintf( name
, "#chat_%03d", i
);
567 if( ( ic
= irc_channel_new( irc
, name
) ) )
577 topic
= g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c
->title
);
578 irc_channel_set_topic( ic
, topic
, irc
->root
);
584 static gboolean
bee_irc_chat_free( bee_t
*bee
, struct groupchat
*c
)
586 irc_channel_t
*ic
= c
->ui_data
;
591 if( ic
->flags
& IRC_CHANNEL_JOINED
)
592 irc_channel_printf( ic
, "Cleaning up channel, bye!" );
596 irc_channel_del_user( ic
, ic
->irc
->user
, IRC_CDU_KICK
, "Chatroom closed by server" );
601 static gboolean
bee_irc_chat_log( bee_t
*bee
, struct groupchat
*c
, const char *text
)
603 irc_channel_t
*ic
= c
->ui_data
;
608 irc_channel_printf( ic
, "%s", text
);
613 static gboolean
bee_irc_chat_msg( bee_t
*bee
, struct groupchat
*c
, bee_user_t
*bu
, const char *msg
, time_t sent_at
)
615 irc_t
*irc
= bee
->ui_data
;
616 irc_user_t
*iu
= bu
->ui_data
;
617 irc_channel_t
*ic
= c
->ui_data
;
623 if( sent_at
> 0 && set_getbool( &bee
->set
, "display_timestamps" ) )
624 ts
= irc_format_timestamp( irc
, sent_at
);
626 irc_send_msg( iu
, "PRIVMSG", ic
->name
, msg
, ts
);
632 static gboolean
bee_irc_chat_add_user( bee_t
*bee
, struct groupchat
*c
, bee_user_t
*bu
)
634 irc_t
*irc
= bee
->ui_data
;
635 irc_channel_t
*ic
= c
->ui_data
;
640 irc_channel_add_user( ic
, bu
== bee
->user
? irc
->user
: bu
->ui_data
);
645 static gboolean
bee_irc_chat_remove_user( bee_t
*bee
, struct groupchat
*c
, bee_user_t
*bu
)
647 irc_t
*irc
= bee
->ui_data
;
648 irc_channel_t
*ic
= c
->ui_data
;
650 if( ic
== NULL
|| bu
== NULL
)
653 /* TODO: Possible bug here: If a module removes $user here instead of just
654 using imcb_chat_free() and the channel was IRC_CHANNEL_TEMP, we get into
655 a broken state around here. */
656 irc_channel_del_user( ic
, bu
== bee
->user
? irc
->user
: bu
->ui_data
, IRC_CDU_PART
, NULL
);
661 static gboolean
bee_irc_chat_topic( bee_t
*bee
, struct groupchat
*c
, const char *new, bee_user_t
*bu
)
663 irc_channel_t
*ic
= c
->ui_data
;
664 irc_t
*irc
= bee
->ui_data
;
672 else if( bu
== bee
->user
)
677 irc_channel_set_topic( ic
, new, iu
);
682 static gboolean
bee_irc_chat_name_hint( bee_t
*bee
, struct groupchat
*c
, const char *name
)
684 irc_t
*irc
= bee
->ui_data
;
685 irc_channel_t
*ic
= c
->ui_data
, *oic
;
686 char stripped
[MAX_NICK_LENGTH
+1], *full_name
;
691 /* Don't rename a channel if the user's in it already. */
692 if( ic
->flags
& IRC_CHANNEL_JOINED
)
695 strncpy( stripped
, name
, MAX_NICK_LENGTH
);
696 stripped
[MAX_NICK_LENGTH
] = '\0';
697 irc_channel_name_strip( stripped
);
698 if( set_getbool( &bee
->set
, "lcnicks" ) )
701 if( stripped
[0] == '\0' )
704 full_name
= g_strdup_printf( "#%s", stripped
);
705 if( ( oic
= irc_channel_by_name( irc
, full_name
) ) )
707 char *type
, *chat_type
;
709 type
= set_getstr( &oic
->set
, "type" );
710 chat_type
= set_getstr( &oic
->set
, "chat_type" );
712 if( type
&& chat_type
&& oic
->data
== FALSE
&&
713 strcmp( type
, "chat" ) == 0 &&
714 strcmp( chat_type
, "groupchat" ) == 0 )
716 /* There's a channel with this name already, but it looks
717 like it's not in use yet. Most likely the IRC client
718 rejoined the channel after a reconnect. Remove it so
719 we can reuse its name. */
720 irc_channel_free( oic
);
730 ic
->name
= full_name
;
735 static gboolean
bee_irc_chat_invite( bee_t
*bee
, bee_user_t
*bu
, const char *name
, const char *msg
)
738 irc_t
*irc
= bee
->ui_data
;
739 irc_user_t
*iu
= bu
->ui_data
;
742 if( strchr( CTYPES
, name
[0] ) )
743 channel
= g_strdup( name
);
745 channel
= g_strdup_printf( "#%s", name
);
747 if( ( s
= strchr( channel
, '@' ) ) )
750 if( strlen( channel
) > MAX_NICK_LENGTH
)
752 /* If the channel name is very long (like those insane GTalk
753 UUID names), try if we can use the inviter's nick. */
754 s
= g_strdup_printf( "#%s", iu
->nick
);
755 if( irc_channel_by_name( irc
, s
) == NULL
)
762 if( ( chan
= irc_channel_new( irc
, channel
) ) &&
763 set_setstr( &chan
->set
, "type", "chat" ) &&
764 set_setstr( &chan
->set
, "chat_type", "room" ) &&
765 set_setstr( &chan
->set
, "account", bu
->ic
->acc
->tag
) &&
766 set_setstr( &chan
->set
, "room", (char*) name
) )
768 /* I'm assuming that if the user didn't "chat add" the room
769 himself but got invited, it's temporary, so make this a
770 temporary mapping that is removed as soon as we /PART. */
771 chan
->flags
|= IRC_CHANNEL_TEMP
;
775 irc_channel_free( chan
);
780 irc_send_msg_f( iu
, "PRIVMSG", irc
->user
->nick
, "<< \002BitlBee\002 - Invitation to chatroom %s >>", name
);
782 irc_send_msg( iu
, "PRIVMSG", irc
->user
->nick
, msg
, NULL
);
785 irc_send_msg_f( iu
, "PRIVMSG", irc
->user
->nick
, "To join the room, just /join %s", chan
->name
);
786 irc_send_invite( iu
, chan
);
793 static gboolean
bee_irc_channel_chat_privmsg_cb( gpointer data
, gint fd
, b_input_condition cond
);
795 static gboolean
bee_irc_channel_chat_privmsg( irc_channel_t
*ic
, const char *msg
)
797 struct groupchat
*c
= ic
->data
;
798 char *trans
= NULL
, *s
;
803 if( set_getbool( &ic
->set
, "translate_to_nicks" ) )
805 char nick
[MAX_NICK_LENGTH
+1];
808 strncpy( nick
, msg
, MAX_NICK_LENGTH
);
809 nick
[MAX_NICK_LENGTH
] = '\0';
810 if( ( s
= strchr( nick
, ':' ) ) || ( s
= strchr( nick
, ',' ) ) )
813 if( ( iu
= irc_user_by_name( ic
->irc
, nick
) ) && iu
->bu
&&
814 iu
->bu
->nick
&& irc_channel_has_user( ic
, iu
) )
816 trans
= g_strconcat( iu
->bu
->nick
, msg
+ ( s
- nick
), NULL
);
822 if( set_getbool( &ic
->irc
->b
->set
, "paste_buffer" ) )
826 if( ic
->pastebuf
== NULL
)
827 ic
->pastebuf
= g_string_new( msg
);
830 b_event_remove( ic
->pastebuf_timer
);
831 g_string_append_printf( ic
->pastebuf
, "\n%s", msg
);
834 if( ( delay
= set_getint( &ic
->irc
->b
->set
, "paste_buffer_delay" ) ) <= 5 )
837 ic
->pastebuf_timer
= b_timeout_add( delay
, bee_irc_channel_chat_privmsg_cb
, ic
);
843 bee_chat_msg( ic
->irc
->b
, c
, msg
, 0 );
849 static gboolean
bee_irc_channel_chat_privmsg_cb( gpointer data
, gint fd
, b_input_condition cond
)
851 irc_channel_t
*ic
= data
;
854 bee_chat_msg( ic
->irc
->b
, ic
->data
, ic
->pastebuf
->str
, 0 );
856 g_string_free( ic
->pastebuf
, TRUE
);
858 ic
->pastebuf_timer
= 0;
863 static gboolean
bee_irc_channel_chat_join( irc_channel_t
*ic
)
868 if( strcmp( set_getstr( &ic
->set
, "chat_type" ), "room" ) != 0 )
871 if( ( acc_s
= set_getstr( &ic
->set
, "account" ) ) &&
872 ( room
= set_getstr( &ic
->set
, "room" ) ) &&
873 ( acc
= account_get( ic
->irc
->b
, acc_s
) ) &&
874 acc
->ic
&& acc
->prpl
->chat_join
)
878 if( !( nick
= set_getstr( &ic
->set
, "nick" ) ) )
879 nick
= ic
->irc
->user
->nick
;
881 ic
->flags
|= IRC_CHANNEL_CHAT_PICKME
;
882 acc
->prpl
->chat_join( acc
->ic
, room
, nick
, NULL
, &ic
->set
);
883 ic
->flags
&= ~IRC_CHANNEL_CHAT_PICKME
;
889 irc_send_num( ic
->irc
, 403, "%s :Can't join channel, account offline?", ic
->name
);
894 static gboolean
bee_irc_channel_chat_part( irc_channel_t
*ic
, const char *msg
)
896 struct groupchat
*c
= ic
->data
;
898 if( c
&& c
->ic
->acc
->prpl
->chat_leave
)
899 c
->ic
->acc
->prpl
->chat_leave( c
);
901 /* Remove references in both directions now. We don't need each other anymore. */
909 static gboolean
bee_irc_channel_chat_topic( irc_channel_t
*ic
, const char *new )
911 struct groupchat
*c
= ic
->data
;
916 if( c
->ic
->acc
->prpl
->chat_topic
== NULL
)
917 irc_send_num( ic
->irc
, 482, "%s :IM network does not support channel topics", ic
->name
);
920 /* TODO: Need more const goodness here, sigh */
921 char *topic
= g_strdup( new );
922 c
->ic
->acc
->prpl
->chat_topic( c
, topic
);
926 /* Whatever happened, the IM module should ack the topic change. */
930 static gboolean
bee_irc_channel_chat_invite( irc_channel_t
*ic
, irc_user_t
*iu
)
932 struct groupchat
*c
= ic
->data
;
933 bee_user_t
*bu
= iu
->bu
;
940 if( iu
->bu
->ic
!= c
->ic
)
941 irc_send_num( ic
->irc
, 482, "%s :Can't mix different IM networks in one groupchat", ic
->name
);
942 else if( c
->ic
->acc
->prpl
->chat_invite
)
943 c
->ic
->acc
->prpl
->chat_invite( c
, iu
->bu
->handle
, NULL
);
945 irc_send_num( ic
->irc
, 482, "%s :IM protocol does not support room invitations", ic
->name
);
947 else if( bu
->ic
->acc
->prpl
->chat_with
&&
948 strcmp( set_getstr( &ic
->set
, "chat_type" ), "groupchat" ) == 0 )
950 ic
->flags
|= IRC_CHANNEL_CHAT_PICKME
;
951 iu
->bu
->ic
->acc
->prpl
->chat_with( bu
->ic
, bu
->handle
);
952 ic
->flags
&= ~IRC_CHANNEL_CHAT_PICKME
;
956 irc_send_num( ic
->irc
, 482, "%s :IM protocol does not support room invitations", ic
->name
);
962 static char *set_eval_room_account( set_t
*set
, char *value
);
963 static char *set_eval_chat_type( set_t
*set
, char *value
);
965 static gboolean
bee_irc_channel_init( irc_channel_t
*ic
)
969 set_add( &ic
->set
, "account", NULL
, set_eval_room_account
, ic
);
970 set_add( &ic
->set
, "chat_type", "groupchat", set_eval_chat_type
, ic
);
972 s
= set_add( &ic
->set
, "nick", NULL
, NULL
, ic
);
973 s
->flags
|= SET_NULL_OK
;
975 set_add( &ic
->set
, "room", NULL
, NULL
, ic
);
976 set_add( &ic
->set
, "translate_to_nicks", "true", set_eval_bool
, ic
);
978 /* chat_type == groupchat */
979 ic
->flags
|= IRC_CHANNEL_TEMP
;
984 static char *set_eval_room_account( set_t
*set
, char *value
)
986 struct irc_channel
*ic
= set
->data
;
989 if( !( acc
= account_get( ic
->irc
->b
, value
) ) )
991 else if( !acc
->prpl
->chat_join
)
993 irc_rootmsg( ic
->irc
, "Named chatrooms not supported on that account." );
997 if( set
->value
&& ( oa
= account_get( ic
->irc
->b
, set
->value
) ) &&
998 oa
->prpl
->chat_free_settings
)
999 oa
->prpl
->chat_free_settings( oa
, &ic
->set
);
1001 if( acc
->prpl
->chat_add_settings
)
1002 acc
->prpl
->chat_add_settings( acc
, &ic
->set
);
1004 return g_strdup( acc
->tag
);
1007 static char *set_eval_chat_type( set_t
*set
, char *value
)
1009 struct irc_channel
*ic
= set
->data
;
1011 if( strcmp( value
, "groupchat" ) == 0 )
1012 ic
->flags
|= IRC_CHANNEL_TEMP
;
1013 else if( strcmp( value
, "room" ) == 0 )
1014 ic
->flags
&= ~IRC_CHANNEL_TEMP
;
1021 static gboolean
bee_irc_channel_free( irc_channel_t
*ic
)
1023 struct groupchat
*c
= ic
->data
;
1025 set_del( &ic
->set
, "account" );
1026 set_del( &ic
->set
, "chat_type" );
1027 set_del( &ic
->set
, "nick" );
1028 set_del( &ic
->set
, "room" );
1029 set_del( &ic
->set
, "translate_to_nicks" );
1031 ic
->flags
&= ~IRC_CHANNEL_TEMP
;
1033 /* That one still points at this channel. Don't. */
1040 const struct irc_channel_funcs irc_channel_im_chat_funcs
= {
1041 bee_irc_channel_chat_privmsg
,
1042 bee_irc_channel_chat_join
,
1043 bee_irc_channel_chat_part
,
1044 bee_irc_channel_chat_topic
,
1045 bee_irc_channel_chat_invite
,
1047 bee_irc_channel_init
,
1048 bee_irc_channel_free
,
1052 /* IM->IRC: File transfers */
1053 static file_transfer_t
*bee_irc_ft_in_start( bee_t
*bee
, bee_user_t
*bu
, const char *file_name
, size_t file_size
)
1055 return dccs_send_start( bu
->ic
, (irc_user_t
*) bu
->ui_data
, file_name
, file_size
);
1058 static gboolean
bee_irc_ft_out_start( struct im_connection
*ic
, file_transfer_t
*ft
)
1060 return dccs_recv_start( ft
);
1063 static void bee_irc_ft_close( struct im_connection
*ic
, file_transfer_t
*ft
)
1065 return dcc_close( ft
);
1068 static void bee_irc_ft_finished( struct im_connection
*ic
, file_transfer_t
*file
)
1070 dcc_file_transfer_t
*df
= file
->priv
;
1072 if( file
->bytes_transferred
>= file
->file_size
)
1075 df
->proto_finished
= TRUE
;
1078 const struct bee_ui_funcs irc_ui_funcs
= {
1079 bee_irc_imc_connected
,
1080 bee_irc_imc_disconnected
,
1084 bee_irc_user_fullname
,
1085 bee_irc_user_nick_hint
,
1087 bee_irc_user_status
,
1089 bee_irc_user_typing
,
1090 bee_irc_user_action_response
,
1096 bee_irc_chat_add_user
,
1097 bee_irc_chat_remove_user
,
1099 bee_irc_chat_name_hint
,
1100 bee_irc_chat_invite
,
1102 bee_irc_ft_in_start
,
1103 bee_irc_ft_out_start
,
1105 bee_irc_ft_finished
,