1 /* $Id: jabber.c,v 1.24 2004/04/13 17:44:07 jajcus Exp $ */
2
3 /*
4 * (C) Copyright 2002-2013 Jacek Konieczny [jajcus(a)jajcus,net]
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License Version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "ggtrans.h"
21 #include "jabber.h"
22 #include "stream.h"
23 #include "iq.h"
24 #include "presence.h"
25 #include "message.h"
26 #include "users.h"
27 #include "conf.h"
28
29 GSource * jabber_source=NULL;
30 Stream *stream=NULL;
31 char *stream_id=NULL;
32 const char *secret;
33 const char *my_name;
34 int bare_domain = 0;
35 int stop_it;
36
37 enum jabber_state_e jabber_state;
38
jabber_stream_start(Stream * s,xmlnode x)39 void jabber_stream_start(Stream *s,xmlnode x){
40 char hashbuf[50];
41 char *str;
42 xmlnode tag;
43
44 if (jabber_state!=JS_NONE){
45 g_warning(N_("unexpected <stream:stream/>"));
46 return;
47 }
48
49 stream_id=xmlnode_get_attrib(x,"id");
50 str=g_strdup_printf("%s%s",stream_id,secret);
51 shahash_r(str,hashbuf);
52 g_free(str);
53 tag=xmlnode_new_tag("handshake");
54 xmlnode_insert_cdata(tag,hashbuf,-1);
55 stream_write(s,tag);
56 xmlnode_free(tag);
57 jabber_state=JS_HANDSHAKE;
58 }
59
jabber_handshake(Stream * s,xmlnode x)60 void jabber_handshake(Stream *s,xmlnode x){
61
62 if (jabber_state!=JS_HANDSHAKE){
63 g_warning(N_("unexpected <hanshake/>"));
64 return;
65 }
66
67 g_message("%s", L_("handshake OK"));
68 jabber_state=JS_CONNECTED;
69 users_probe_all();
70 }
71
jabber_stream_error(Stream * s,xmlnode x)72 void jabber_stream_error(Stream *s,xmlnode x){
73 char *data;
74
75 data=xmlnode_get_data(x);
76 if (data==NULL) data="-unknown-";
77 g_critical(L_("Stream error: %s"),data);
78 stream_close(s);
79 stop_it=1;
80 }
81
jabber_stream()82 struct stream_s * jabber_stream(){
83 return stream;
84 }
85
jabber_node(Stream * s,xmlnode x)86 void jabber_node(Stream *s,xmlnode x){
87 char *name;
88
89 packets_in++;
90 name=xmlnode_get_name(x);
91 if (strcmp(name,"stream:stream")==0)
92 jabber_stream_start(s,x);
93 else if (strcmp(name,"handshake")==0)
94 jabber_handshake(s,x);
95 else if (strcmp(name,"stream:error")==0)
96 jabber_stream_error(s,x);
97 else if (strcmp(name,"iq")==0)
98 jabber_iq(s,x);
99 else if (strcmp(name,"presence")==0)
100 jabber_presence(s,x);
101 else if (strcmp(name,"message")==0)
102 jabber_message(s,x);
103 else g_warning(N_("Unsupported tag: %s"),xmlnode2str(x));
104 xmlnode_free(x);
105 }
106
jabber_event_cb(int type,xmlnode x,void * arg)107 void jabber_event_cb(int type,xmlnode x,void *arg){
108 Stream *s;
109 char *data;
110
111 if (stop_it || !stream) return;
112
113 s=(Stream *)arg;
114 switch(type){
115 case XSTREAM_ROOT:
116 jabber_node(s,x);
117 break;
118 case XSTREAM_CLOSE:
119 if (x || !stop_it){
120 stop_it=1;
121 stream_close(s);
122 }
123 else stop_it=2;
124 break;
125 case XSTREAM_NODE:
126 jabber_node(s,x);
127 break;
128 case XSTREAM_ERR:
129 g_warning(N_("Stream Error"));
130 if (x){
131 data=xmlnode_get_data(x);
132 if (data==NULL) data="-unknown-";
133 g_warning(" %s",data);
134 }
135 break;
136 default:
137 g_critical(L_("Unknown node type: %i"),type);
138 stop_it=1;
139 stream_close(s);
140 break;
141 }
142 }
143
jabber_source_prepare(GSource * source,gint * timeout)144 gboolean jabber_source_prepare(GSource *source,
145 gint *timeout){
146
147 *timeout=1000;
148 if (stop_it || stream==NULL) return TRUE;
149 return FALSE;
150 }
151
jabber_source_check(GSource * source)152 gboolean jabber_source_check(GSource *source){
153
154 if (stop_it || stream==NULL) return TRUE;
155 return FALSE;
156 }
157
jabber_source_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)158 gboolean jabber_source_dispatch(GSource *source,
159 GSourceFunc callback,
160 gpointer user_data){
161
162 if (stop_it && stream){
163 if (stop_it>1){
164 stream_destroy(stream);
165 stream=NULL;
166 g_main_quit(main_loop);
167 }
168 stop_it++;
169 }
170 else if (stream==NULL) g_main_quit(main_loop);
171
172 return TRUE;
173 }
174
jabber_source_finalize(GSource * source)175 void jabber_source_finalize(GSource *source){
176 }
177
178 static GSourceFuncs jabber_source_funcs={
179 jabber_source_prepare,
180 jabber_source_check,
181 jabber_source_dispatch,
182 jabber_source_finalize,
183 NULL,
184 NULL
185 };
186
jabber_stream_destroyed(struct stream_s * s)187 void jabber_stream_destroyed(struct stream_s *s){
188
189 if (s==stream) stream=NULL;
190 }
191
jabber_done()192 int jabber_done(){
193
194 if (stream){
195 stream_destroy(stream);
196 stream=NULL;
197 }
198 if (jabber_source){
199 g_source_destroy(jabber_source);
200 }
201 g_free(register_instructions);
202 g_free(search_instructions);
203 g_free(gateway_desc);
204 g_free(gateway_prompt);
205 stream_del_destroy_handler(jabber_stream_destroyed);
206 return 0;
207 }
208
209 static char *server;
210 static int port;
211
jabber_init()212 int jabber_init(){
213 xmlnode node;
214
215 stream_add_destroy_handler(jabber_stream_destroyed);
216 node=xmlnode_get_tag(config,"service");
217 if (!node)
218 error_exit("%s", L_("No <service/> found in config file"));
219
220 my_name=xmlnode_get_attrib(node,"jid");
221 if (!my_name)
222 error_exit("%s", L_("<service/> without \"jid\" in config file"));
223
224 node=xmlnode_get_tag(config, "bare_domain");
225 if (node) bare_domain=1;
226
227 server=config_load_string("connect/ip");
228 if (!server)
229 error_exit("%s", L_("Jabberd server not found in config file"));
230
231 port=config_load_int("connect/port",0);
232 if (port<=0)
233 error_exit("%s", L_("Connect port not found in config file"));
234
235 node=xmlnode_get_tag(config,"connect/secret");
236 if (node) secret=xmlnode_get_data(node);
237 if (!node || !secret)
238 error_exit("%s", L_("Connect secret not found in config file"));
239
240 register_instructions=config_load_formatted_string("register/instructions");
241 if (!register_instructions)
242 error_exit("%s", L_("Registration instructions not not found in config file"));
243
244 search_instructions=config_load_formatted_string("search/instructions");
245 if (!search_instructions)
246 error_exit("%s", L_("Search instructions not found in config file"));
247
248 gateway_desc=config_load_formatted_string("gateway/desc");
249 if (!gateway_desc)
250 error_exit("%s", L_("Gateway instructions not found in config file"));
251
252 gateway_prompt=config_load_formatted_string("gateway/prompt");
253 if (!gateway_prompt)
254 error_exit("%s", L_("Gateway prompt not found in config file"));
255
256 jabber_state=JS_NONE;
257 return 0;
258 }
259
jabber_connect()260 int jabber_connect(){
261
262 stream=stream_connect(server,port,1,jabber_event_cb);
263 g_assert(stream!=NULL);
264 jabber_source=g_source_new(&jabber_source_funcs,sizeof(GSource));
265 g_source_attach(jabber_source,g_main_loop_get_context(main_loop));
266 return 0;
267 }
268
269