1 /**
2  * @file jabber.h
3  *
4  * purple
5  *
6  * Purple is the legal property of its developers, whose names are too numerous
7  * to list here.  Please refer to the COPYRIGHT file distributed with this
8  * source distribution.
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
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
23  */
24 #ifndef PURPLE_JABBER_H_
25 #define PURPLE_JABBER_H_
26 
27 typedef enum {
28 	JABBER_CAP_NONE           = 0,
29 /*	JABBER_CAP_XHTML          = 1 << 0, */
30 /*	JABBER_CAP_COMPOSING      = 1 << 1, */
31 	JABBER_CAP_SI             = 1 << 2,
32 	JABBER_CAP_SI_FILE_XFER   = 1 << 3,
33 	JABBER_CAP_BYTESTREAMS    = 1 << 4,
34 	JABBER_CAP_IBB            = 1 << 5,
35 	JABBER_CAP_CHAT_STATES    = 1 << 6,
36 	JABBER_CAP_IQ_SEARCH      = 1 << 7,
37 	JABBER_CAP_IQ_REGISTER    = 1 << 8,
38 
39 	/* Google Talk extensions:
40 	 * http://code.google.com/apis/talk/jep_extensions/extensions.html
41 	 */
42 	JABBER_CAP_GMAIL_NOTIFY   = 1 << 9,
43 	JABBER_CAP_GOOGLE_ROSTER  = 1 << 10,
44 
45 	JABBER_CAP_PING			  = 1 << 11,
46 	JABBER_CAP_ADHOC		  = 1 << 12,
47 	JABBER_CAP_BLOCKING       = 1 << 13,
48 
49 	JABBER_CAP_ITEMS          = 1 << 14,
50 	JABBER_CAP_ROSTER_VERSIONING = 1 << 15,
51 
52 	JABBER_CAP_STREAM_MANAGEMENT = 1 << 16,
53 
54 	JABBER_CAP_RETRIEVED      = 1 << 31
55 } JabberCapabilities;
56 
57 typedef struct _JabberStream JabberStream;
58 
59 #include <libxml/parser.h>
60 #include <glib.h>
61 #include "circbuffer.h"
62 #include "connection.h"
63 #include "dnsquery.h"
64 #include "dnssrv.h"
65 #include "media.h"
66 #include "mediamanager.h"
67 #include "roomlist.h"
68 #include "sslconn.h"
69 
70 #include "namespaces.h"
71 
72 #include "auth.h"
73 #include "iq.h"
74 #include "jutil.h"
75 #include "xmlnode.h"
76 #include "buddy.h"
77 #include "bosh.h"
78 
79 #ifdef HAVE_CYRUS_SASL
80 #include <sasl/sasl.h>
81 #endif
82 
83 #define CAPS0115_NODE "http://pidgin.im/"
84 
85 #define JABBER_DEFAULT_REQUIRE_TLS    "require_starttls"
86 #define JABBER_DEFAULT_FT_PROXIES     ""
87 
88 /* Index into attention_types list */
89 #define JABBER_BUZZ 0
90 
91 typedef enum {
92 	JABBER_STREAM_OFFLINE,
93 	JABBER_STREAM_CONNECTING,
94 	JABBER_STREAM_INITIALIZING,
95 	JABBER_STREAM_INITIALIZING_ENCRYPTION,
96 	JABBER_STREAM_AUTHENTICATING,
97 	JABBER_STREAM_POST_AUTH,
98 	JABBER_STREAM_CONNECTED
99 } JabberStreamState;
100 
101 typedef enum {
102 	SM_DISABLED,
103 	SM_PLANNED,
104 	SM_REQUESTED,
105 	SM_ENABLED
106 } JabberStreamManagementState;
107 
108 struct _JabberStream
109 {
110 	int fd;
111 
112 	PurpleSrvTxtQueryData *srv_query_data;
113 
114 	xmlParserCtxt *context;
115 	xmlnode *current;
116 
117 	struct {
118 		guint8 major;
119 		guint8 minor;
120 	} protocol_version;
121 
122 	JabberSaslMech *auth_mech;
123 	gpointer auth_mech_data;
124 
125 	/**
126 	 * The header from the opening <stream/> tag.  This being NULL is treated
127 	 * as a special condition in the parsing code (signifying the next
128 	 * stanza started is an opening stream tag), and its being missing on
129 	 * the stream header is treated as a fatal error.
130 	 */
131 	char *stream_id;
132 	JabberStreamState state;
133 
134 	GHashTable *buddies;
135 
136 	/*
137 	 * This boolean was added to eliminate a heinous bug where we would
138 	 * get into a loop with the server and move a buddy back and forth
139 	 * from one group to another.
140 	 *
141 	 * The sequence goes something like this:
142 	 * 1. Our resource and another resource both approve an authorization
143 	 *    request at the exact same time.  We put the buddy in group A and
144 	 *    the other resource put the buddy in group B.
145 	 * 2. The server receives the roster add for group B and sends us a
146 	 *    roster push.
147 	 * 3. We receive this roster push and modify our local blist.  This
148 	 *    triggers us to send a roster add for group B.
149 	 * 4. The server recieves our earlier roster add for group A and sends
150 	 *    us a roster push.
151 	 * 5. We receive this roster push and modify our local blist.  This
152 	 *    triggers us to send a roster add for group A.
153 	 * 6. The server receives our earlier roster add for group B and sends
154 	 *    us a roster push.
155 	 * (repeat steps 3 through 6 ad infinitum)
156 	 *
157 	 * This boolean is used to short-circuit the sending of a roster add
158 	 * when we receive a roster push.
159 	 *
160 	 * See these bug reports:
161 	 * http://trac.adiumx.com/ticket/8834
162 	 * http://developer.pidgin.im/ticket/5484
163 	 * http://developer.pidgin.im/ticket/6188
164 	 */
165 	gboolean currently_parsing_roster_push;
166 
167 	GHashTable *chats;
168 	GList *chat_servers;
169 	PurpleRoomlist *roomlist;
170 	GList *user_directories;
171 
172 	GHashTable *iq_callbacks;
173 	int next_id;
174 
175 	GList *bs_proxies;
176 	GList *oob_file_transfers;
177 	GList *file_transfers;
178 
179 	time_t idle;
180 	time_t old_idle;
181 
182 	/** When we last pinged the server, so we don't ping more
183 	 *  often than once every minute.
184 	 */
185 	time_t last_ping;
186 
187 	JabberID *user;
188 	JabberBuddy *user_jb;
189 
190 	PurpleConnection *gc;
191 	PurpleSslConnection *gsc;
192 
193 	gboolean registration;
194 
195 	char *initial_avatar_hash;
196 	char *avatar_hash;
197 	GSList *pending_avatar_requests;
198 
199 	GSList *pending_buddy_info_requests;
200 
201 	PurpleCircBuffer *write_buffer;
202 	guint writeh;
203 
204 	gboolean reinit;
205 
206 	JabberCapabilities server_caps;
207 	gboolean googletalk;
208 	char *server_name;
209 
210 	char *gmail_last_time;
211 	char *gmail_last_tid;
212 
213 	char *serverFQDN;
214 
215 #ifdef HAVE_CYRUS_SASL
216 	sasl_conn_t *sasl;
217 	sasl_callback_t *sasl_cb;
218 	sasl_secret_t *sasl_secret;
219 	const char *current_mech;
220 	int auth_fail_count;
221 
222 	int sasl_state;
223 	int sasl_maxbuf;
224 	GString *sasl_mechs;
225 #endif
226 
227 	gboolean unregistration;
228 	PurpleAccountUnregistrationCb unregistration_cb;
229 	void *unregistration_user_data;
230 
231 	gboolean vcard_fetched;
232 	/* Timer at login to push updated avatar */
233 	guint vcard_timer;
234 
235 	/* Entity Capabilities hash */
236 	char *caps_hash;
237 
238 	/* does the local server support PEP? */
239 	gboolean pep;
240 
241 	/* Is Buzz enabled? */
242 	gboolean allowBuzz;
243 
244 	/* A list of JabberAdHocCommands supported by the server */
245 	GList *commands;
246 
247 	/* last presence update to check for differences */
248 	JabberBuddyState old_state;
249 	char *old_msg;
250 	int old_priority;
251 	char *old_avatarhash;
252 
253 	/* same for user tune */
254 	char *old_artist;
255 	char *old_title;
256 	char *old_source;
257 	char *old_uri;
258 	int old_length;
259 	char *old_track;
260 
261 	char *certificate_CN;
262 
263 	/* A purple timeout tag for the keepalive */
264 	guint keepalive_timeout;
265 	guint max_inactivity;
266 	guint inactivity_timer;
267 
268 	PurpleSrvResponse *srv_rec;
269 	guint srv_rec_idx;
270 	guint max_srv_rec_idx;
271 
272 	/* BOSH stuff */
273 	PurpleBOSHConnection *bosh;
274 
275 	/**
276 	 * This linked list contains PurpleUtilFetchUrlData structs
277 	 * for when we lookup buddy icons from a url
278 	 */
279 	GSList *url_datas;
280 
281 	/* keep a hash table of JingleSessions */
282 	GHashTable *sessions;
283 
284 	/* maybe this should only be present when USE_VV? */
285 	gchar *stun_ip;
286 	int stun_port;
287 	PurpleDnsQueryData *stun_query;
288 
289 	/* stuff for Google's relay handling */
290 	gchar *google_relay_token;
291 	gchar *google_relay_host;
292 	GList *google_relay_requests; /* the HTTP requests to get */
293 												/* relay info */
294 
295 	/* XEP-0198 (stream management) state */
296 	guint32 sm_outbound_count;
297 	guint32 sm_inbound_count;
298 	guint32 sm_outbound_confirmed;
299 	JabberStreamManagementState sm_state;
300 };
301 
302 typedef gboolean (JabberFeatureEnabled)(JabberStream *js, const gchar *namespace);
303 
304 typedef struct _JabberFeature
305 {
306 	gchar *namespace;
307 	JabberFeatureEnabled *is_enabled;
308 } JabberFeature;
309 
310 typedef struct _JabberIdentity
311 {
312 	gchar *category;
313 	gchar *type;
314 	gchar *name;
315 	gchar *lang;
316 } JabberIdentity;
317 
318 typedef struct _JabberBytestreamsStreamhost {
319 	char *jid;
320 	char *host;
321 	int port;
322 	char *zeroconf;
323 } JabberBytestreamsStreamhost;
324 
325 /* what kind of additional features as returned from disco#info are supported? */
326 extern GList *jabber_features;
327 /* A sorted list of identities advertised.  Use jabber_add_identity to add
328  * so it remains sorted.
329  */
330 extern GList *jabber_identities;
331 
332 gboolean jabber_is_stanza(xmlnode *packet);
333 
334 void jabber_stream_features_parse(JabberStream *js, xmlnode *packet);
335 void jabber_process_packet(JabberStream *js, xmlnode **packet);
336 void jabber_send(JabberStream *js, xmlnode *data);
337 void jabber_send_raw(JabberStream *js, const char *data, int len);
338 void jabber_send_signal_cb(PurpleConnection *pc, xmlnode **packet,
339                            gpointer unused);
340 
341 void jabber_stream_set_state(JabberStream *js, JabberStreamState state);
342 
343 void jabber_register_parse(JabberStream *js, const char *from,
344                            JabberIqType type, const char *id, xmlnode *query);
345 void jabber_register_start(JabberStream *js);
346 
347 char *jabber_get_next_id(JabberStream *js);
348 
349 /** Parse an error into a human-readable string and optionally a disconnect
350  *  reason.
351  *  @param js     the stream on which the error occurred.
352  *  @param packet the error packet
353  *  @param reason where to store the disconnection reason, or @c NULL if you
354  *                don't care or you don't intend to close the connection.
355  */
356 char *jabber_parse_error(JabberStream *js, xmlnode *packet, PurpleConnectionError *reason);
357 
358 /**
359  * Add a feature to the list of features advertised via disco#info.  If you
360  * call this while accounts are connected, Bad Things(TM) will happen because
361  * the Entity Caps hash will be out-of-date (which should be fixed :/)
362  *
363  * @param namespace The namespace of the feature
364  * @param cb        A callback determining whether or not this feature
365  *                  will advertised; may be NULL.
366  */
367 void jabber_add_feature(const gchar *namespace, JabberFeatureEnabled cb);
368 void jabber_remove_feature(const gchar *namespace);
369 
370 /** Adds an identity to this jabber library instance. For list of valid values
371  * visit the website of the XMPP Registrar
372  * (http://www.xmpp.org/registrar/disco-categories.html#client).
373  *
374  * Like with jabber_add_feature, if you call this while accounts are connected,
375  * Bad Things will happen.
376  *
377  *  @param category the category of the identity.
378  *  @param type the type of the identity.
379  *  @param language the language localization of the name. Can be NULL.
380  *  @param name the name of the identity.
381  */
382 void jabber_add_identity(const gchar *category, const gchar *type, const gchar *lang, const gchar *name);
383 
384 /**
385  * GCompareFunc for JabberIdentity structs.
386  */
387 gint jabber_identity_compare(gconstpointer a, gconstpointer b);
388 
389 /**
390  * Returns true if this connection is over a secure (SSL) stream. Use this
391  * instead of checking js->gsc because BOSH stores its PurpleSslConnection
392  * members in its own data structure.
393  */
394 gboolean jabber_stream_is_ssl(JabberStream *js);
395 
396 /**
397  * Restart the "we haven't sent anything in a while and should send
398  * something or the server will kick us off" timer (obviously
399  * called when sending something.  It's exposed for BOSH.)
400  */
401 void jabber_stream_restart_inactivity_timer(JabberStream *js);
402 
403 /** PRPL functions */
404 const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b);
405 const char* jabber_list_emblem(PurpleBuddy *b);
406 char *jabber_status_text(PurpleBuddy *b);
407 void jabber_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full);
408 GList *jabber_status_types(PurpleAccount *account);
409 void jabber_login(PurpleAccount *account);
410 void jabber_close(PurpleConnection *gc);
411 void jabber_idle_set(PurpleConnection *gc, int idle);
412 void jabber_blocklist_parse_push(JabberStream *js, const char *from,
413                                  JabberIqType type, const char *id,
414                                  xmlnode *child);
415 void jabber_request_block_list(JabberStream *js);
416 void jabber_add_deny(PurpleConnection *gc, const char *who);
417 void jabber_rem_deny(PurpleConnection *gc, const char *who);
418 void jabber_keepalive(PurpleConnection *gc);
419 void jabber_register_gateway(JabberStream *js, const char *gateway);
420 void jabber_register_account(PurpleAccount *account);
421 void jabber_unregister_account(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data);
422 gboolean jabber_send_attention(PurpleConnection *gc, const char *username, guint code);
423 GList *jabber_attention_types(PurpleAccount *account);
424 void jabber_convo_closed(PurpleConnection *gc, const char *who);
425 PurpleChat *jabber_find_blist_chat(PurpleAccount *account, const char *name);
426 gboolean jabber_offline_message(const PurpleBuddy *buddy);
427 int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len);
428 GList *jabber_actions(PurplePlugin *plugin, gpointer context);
429 
430 gboolean jabber_audio_enabled(JabberStream *js, const char *unused);
431 gboolean jabber_video_enabled(JabberStream *js, const char *unused);
432 gboolean jabber_initiate_media(PurpleAccount *account, const char *who,
433 		PurpleMediaSessionType type);
434 PurpleMediaCaps jabber_get_media_caps(PurpleAccount *account, const char *who);
435 gboolean jabber_can_receive_file(PurpleConnection *gc, const gchar *who);
436 
437 void jabber_plugin_init(PurplePlugin *plugin);
438 void jabber_plugin_uninit(PurplePlugin *plugin);
439 
440 #endif /* PURPLE_JABBER_H_ */
441