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