source: protocols/jabber/conference.c @ 256899f

Last change on this file since 256899f was ef5c185, checked in by Wilmer van der Gaast <wilmer@…>, at 2007-11-19T23:14:39Z

Added Jabber groupchat topic support.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Jabber module - Conference rooms                                         *
5*                                                                           *
6*  Copyright 2007 Wilmer van der Gaast <wilmer@gaast.net>                   *
7*                                                                           *
8*  This program is free software; you can redistribute it and/or modify     *
9*  it under the terms of the GNU General Public License as published by     *
10*  the Free Software Foundation; either version 2 of the License, or        *
11*  (at your option) any later version.                                      *
12*                                                                           *
13*  This program is distributed in the hope that it will be useful,          *
14*  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
16*  GNU General Public License for more details.                             *
17*                                                                           *
18*  You should have received a copy of the GNU General Public License along  *
19*  with this program; if not, write to the Free Software Foundation, Inc.,  *
20*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21*                                                                           *
22\***************************************************************************/
23
24#include "jabber.h"
25
26struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password )
27{
28        struct jabber_chat *jc;
29        struct xt_node *node;
30        struct groupchat *c;
31        char *roomjid;
32       
33        roomjid = g_strdup_printf( "%s/%s", room, nick );
34        node = xt_new_node( "x", NULL, NULL );
35        xt_add_attr( node, "xmlns", XMLNS_MUC );
36        node = jabber_make_packet( "presence", NULL, roomjid, node );
37       
38        if( !jabber_write_packet( ic, node ) )
39        {
40                g_free( roomjid );
41                xt_free_node( node );
42                return NULL;
43        }
44        xt_free_node( node );
45       
46        jc = g_new0( struct jabber_chat, 1 );
47        jc->name = jabber_normalize( room );
48       
49        if( ( jc->me = jabber_buddy_add( ic, roomjid ) ) == NULL )
50        {
51                g_free( roomjid );
52                g_free( jc->name );
53                g_free( jc );
54                return NULL;
55        }
56       
57        /* roomjid isn't normalized yet, and we need an original version
58           of the nick to send a proper presence update. */
59        jc->my_full_jid = roomjid;
60       
61        c = imcb_chat_new( ic, room );
62        c->data = jc;
63       
64        return c;
65}
66
67void jabber_chat_free( struct groupchat *c )
68{
69        struct jabber_chat *jc = c->data;
70       
71        jabber_buddy_remove_bare( c->ic, jc->name );
72       
73        g_free( jc->my_full_jid );
74        g_free( jc->name );
75        g_free( jc );
76       
77        imcb_chat_free( c );
78}
79
80int jabber_chat_msg( struct groupchat *c, char *message, int flags )
81{
82        struct im_connection *ic = c->ic;
83        struct jabber_chat *jc = c->data;
84        struct xt_node *node;
85       
86        node = xt_new_node( "body", message, NULL );
87        node = jabber_make_packet( "message", "groupchat", jc->name, node );
88       
89        if( !jabber_write_packet( ic, node ) )
90        {
91                xt_free_node( node );
92                return 0;
93        }
94        xt_free_node( node );
95       
96        return 1;
97}
98
99int jabber_chat_topic( struct groupchat *c, char *topic )
100{
101        struct im_connection *ic = c->ic;
102        struct jabber_chat *jc = c->data;
103        struct xt_node *node;
104       
105        node = xt_new_node( "subject", topic, NULL );
106        node = jabber_make_packet( "message", "groupchat", jc->name, node );
107       
108        if( !jabber_write_packet( ic, node ) )
109        {
110                xt_free_node( node );
111                return 0;
112        }
113        xt_free_node( node );
114       
115        return 1;
116}
117
118int jabber_chat_leave( struct groupchat *c, const char *reason )
119{
120        struct im_connection *ic = c->ic;
121        struct jabber_chat *jc = c->data;
122        struct xt_node *node;
123       
124        node = xt_new_node( "x", NULL, NULL );
125        xt_add_attr( node, "xmlns", XMLNS_MUC );
126        node = jabber_make_packet( "presence", "unavailable", jc->my_full_jid, node );
127       
128        if( !jabber_write_packet( ic, node ) )
129        {
130                xt_free_node( node );
131                return 0;
132        }
133        xt_free_node( node );
134       
135        return 1;
136}
137
138/* Not really the same syntax as the normal pkt_ functions, but this isn't
139   called by the xmltree parser directly and this way I can add some extra
140   parameters so we won't have to repeat too many things done by the caller
141   already. */
142void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node )
143{
144        struct groupchat *chat;
145        struct xt_node *c;
146        char *type = xt_find_attr( node, "type" );
147        struct jabber_chat *jc;
148        char *s;
149       
150        if( ( chat = jabber_chat_by_name( ic, bud->bare_jid ) ) == NULL )
151        {
152                /* How could this happen?? We could do kill( self, 11 )
153                   now or just wait for the OS to do it. :-) */
154                return;
155        }
156       
157        jc = chat->data;
158       
159        if( type == NULL && !( bud->flags & JBFLAG_IS_CHATROOM ) )
160        {
161                bud->flags |= JBFLAG_IS_CHATROOM;
162                /* If this one wasn't set yet, this buddy just joined the chat.
163                   Slightly hackish way of finding out eh? ;-) */
164               
165                /* This is pretty messy... Here it sets ext_jid to the real
166                   JID of the participant. Works for non-anonymized channels.
167                   Might break if someone joins a chat twice, though. */
168                for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next )
169                        if( ( s = xt_find_attr( c, "xmlns" ) ) &&
170                            ( strcmp( s, XMLNS_MUC_USER ) == 0 ) )
171                        {
172                                c = xt_find_node( c->children, "item" );
173                                if( ( s = xt_find_attr( c, "jid" ) ) )
174                                {
175                                        /* Yay, found what we need. :-) */
176                                        bud->ext_jid = jabber_normalize( s );
177                                        break;
178                                }
179                        }
180               
181                /* Make up some other handle, if necessary. */
182                if( bud->ext_jid == NULL )
183                {
184                        if( bud == jc->me )
185                        {
186                                bud->ext_jid = jabber_normalize( ic->acc->user );
187                        }
188                        else
189                        {
190                                int i;
191                               
192                                /* Don't want the nick to be at the end, so let's
193                                   think of some slightly different notation to use
194                                   for anonymous groupchat participants in BitlBee. */
195                                bud->ext_jid = g_strdup_printf( "%s=%s", bud->resource, bud->bare_jid );
196                               
197                                /* And strip any unwanted characters. */
198                                for( i = 0; bud->resource[i]; i ++ )
199                                        if( bud->ext_jid[i] == '=' || bud->ext_jid[i] == '@' )
200                                                bud->ext_jid[i] = '_';
201                               
202                                /* Some program-specific restrictions. */
203                                imcb_clean_handle( ic, bud->ext_jid );
204                        }
205                        bud->flags |= JBFLAG_IS_ANONYMOUS;
206                }
207               
208                if( bud != jc->me )
209                {
210                        imcb_add_buddy( ic, bud->ext_jid, NULL );
211                        imcb_buddy_nick_hint( ic, bud->ext_jid, bud->resource );
212                }
213               
214                s = strchr( bud->ext_jid, '/' );
215                if( s ) *s = 0; /* Should NEVER be NULL, but who knows... */
216                imcb_chat_add_buddy( chat, bud->ext_jid );
217                if( s ) *s = '/';
218        }
219        else if( type ) /* type can only be NULL or "unavailable" in this function */
220        {
221                s = strchr( bud->ext_jid, '/' );
222                if( s ) *s = 0;
223                imcb_chat_remove_buddy( chat, bud->ext_jid, NULL );
224                if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS )
225                        imcb_remove_buddy( ic, bud->ext_jid, NULL );
226                if( s ) *s = '/';
227               
228                if( bud == jc->me )
229                        jabber_chat_free( chat );
230        }
231}
232
233void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node )
234{
235        struct xt_node *subject = xt_find_node( node->children, "subject" );
236        struct xt_node *body = xt_find_node( node->children, "body" );
237        struct groupchat *chat;
238        char *s;
239       
240        if( bud == NULL )
241        {
242                s = xt_find_attr( node, "from" ); /* pkt_message() already NULL-checked this one. */
243                if( strchr( s, '/' ) == NULL )
244                        /* This is fine, the groupchat itself isn't in jd->buddies. */
245                        imcb_log( ic, "System message from groupchat %s: %s", s, body? body->text : "NULL" );
246                else
247                        /* This, however, isn't fine! */
248                        imcb_log( ic, "Groupchat message from unknown participant %s: %s", s, body ? body->text : "NULL" );
249               
250                return;
251        }
252        else if( ( chat = jabber_chat_by_name( ic, bud->bare_jid ) ) == NULL )
253        {
254                /* How could this happen?? We could do kill( self, 11 )
255                   now or just wait for the OS to do it. :-) */
256                return;
257        }
258       
259        if( subject )
260        {
261                s = strchr( bud->ext_jid, '/' );
262                if( s ) *s = 0;
263                imcb_chat_topic( chat, bud->ext_jid, subject->text_len > 0 ?
264                                 subject->text : NULL, jabber_get_timestamp( node ) );
265                if( s ) *s = '/';
266        }
267        if( body && body->text_len > 0 )
268        {
269                s = strchr( bud->ext_jid, '/' );
270                if( s ) *s = 0;
271                imcb_chat_msg( chat, bud->ext_jid, body->text, 0, jabber_get_timestamp( node ) );
272                if( s ) *s = '/';
273        }
274}
Note: See TracBrowser for help on using the repository browser.