Mercurial > hg
comparison mcabber/src/xmpp_helper.c @ 1598:a087125d8fc8
Replace libjabber with loudmouth
author | franky |
---|---|
date | Sun, 11 Oct 2009 15:38:32 +0200 |
parents | |
children | dcd5d4c75199 |
comparison
equal
deleted
inserted
replaced
1597:4f59a414217e | 1598:a087125d8fc8 |
---|---|
1 /* | |
2 * xmpp_helper.c -- Jabber protocol helper functions | |
3 * | |
4 * Copyright (C) 2008 Frank Zschockelt <mcabber@freakysoft.de> | |
5 * Copyright (C) 2005-2008 Mikael Berthe <mikael@lilotux.net> | |
6 * Some parts initially came from the centericq project: | |
7 * Copyright (C) 2002-2005 by Konstantin Klyagin <konst@konst.org.ua> | |
8 * Some small parts come from the Pidgin project <http://pidgin.im/> | |
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 (at | |
13 * your option) any later version. | |
14 * | |
15 * This program is distributed in the hope that it will be useful, but | |
16 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |
23 * USA | |
24 */ | |
25 | |
26 #include "xmpp_helper.h" | |
27 | |
28 time_t iqlast; // last message/status change time | |
29 | |
30 const gchar* lm_message_node_get_child_value(LmMessageNode *node, | |
31 const gchar *child) | |
32 { | |
33 LmMessageNode *tmp; | |
34 tmp = lm_message_node_find_child(node, child); | |
35 if (tmp) | |
36 return lm_message_node_get_value(tmp); | |
37 else return NULL; | |
38 } | |
39 | |
40 static LmMessageNode *hidden = NULL; | |
41 | |
42 void lm_message_node_hide(LmMessageNode *node) | |
43 { | |
44 LmMessageNode *parent = node->parent, *prev_sibling = node->prev; | |
45 | |
46 if (hidden) { | |
47 hidden->children = hidden->next = hidden->prev = hidden->parent = NULL; | |
48 lm_message_node_unref(hidden); | |
49 } | |
50 | |
51 if (parent->children == node) | |
52 parent->children = node->next; | |
53 if (prev_sibling) | |
54 prev_sibling->next = node->next; | |
55 if (node->next) | |
56 node->next->prev = prev_sibling; | |
57 } | |
58 | |
59 //maybe not a good idea, because it uses internals of loudmouth... | |
60 //it's used for rosternotes/bookmarks | |
61 LmMessageNode *lm_message_node_new(const gchar *name, const gchar *xmlns) | |
62 { | |
63 LmMessageNode *node; | |
64 | |
65 node = g_new0 (LmMessageNode, 1); | |
66 node->name = g_strdup (name); | |
67 node->value = NULL; | |
68 node->raw_mode = FALSE; | |
69 node->attributes = NULL; | |
70 node->next = NULL; | |
71 node->prev = NULL; | |
72 node->parent = NULL; | |
73 node->children = NULL; | |
74 | |
75 node->ref_count = 1; | |
76 lm_message_node_set_attribute(node, "xmlns", xmlns); | |
77 return node; | |
78 } | |
79 | |
80 void lm_message_node_insert_childnode(LmMessageNode *node, | |
81 LmMessageNode *child) | |
82 { | |
83 LmMessageNode *x; | |
84 lm_message_node_deep_ref(child); | |
85 | |
86 if (node->children == NULL) | |
87 node->children = child; | |
88 else { | |
89 for (x = node->children; x->next; x = x->next) | |
90 ; | |
91 x->next = child; | |
92 } | |
93 } | |
94 | |
95 void lm_message_node_deep_ref(LmMessageNode *node) | |
96 { | |
97 if (node == NULL) | |
98 return; | |
99 lm_message_node_ref(node); | |
100 lm_message_node_deep_ref(node->next); | |
101 lm_message_node_deep_ref(node->children); | |
102 } | |
103 | |
104 const gchar* lm_message_get_from(LmMessage *m) | |
105 { | |
106 return lm_message_node_get_attribute(m->node, "from"); | |
107 } | |
108 | |
109 const gchar* lm_message_get_id(LmMessage *m) | |
110 { | |
111 return lm_message_node_get_attribute(m->node, "id"); | |
112 } | |
113 | |
114 static LmMessage *lm_message_new_iq_from_query(LmMessage *m, | |
115 LmMessageSubType type) | |
116 { | |
117 LmMessage *new; | |
118 const char *from = lm_message_node_get_attribute(m->node, "from"); | |
119 const char *id = lm_message_node_get_attribute(m->node, "id"); | |
120 | |
121 new = lm_message_new_with_sub_type(from, LM_MESSAGE_TYPE_IQ, | |
122 type); | |
123 if (id) | |
124 lm_message_node_set_attribute(new->node, "id", id); | |
125 | |
126 return new; | |
127 } | |
128 | |
129 // entity_version() | |
130 // Return a static version string for Entity Capabilities. | |
131 // It should be specific to the client version, please change the id | |
132 // if you alter mcabber's disco support (or add something to the version | |
133 // number) so that it doesn't conflict with the official client. | |
134 const char *entity_version(void) | |
135 { | |
136 static char *ver; | |
137 const char *PVERSION = PACKAGE_VERSION; // "+xxx"; | |
138 | |
139 if (ver) | |
140 return ver; | |
141 | |
142 #ifdef HGCSET | |
143 ver = g_strdup_printf("%s-%s", PVERSION, HGCSET); | |
144 #else | |
145 ver = g_strdup(PVERSION); | |
146 #endif | |
147 | |
148 return ver; | |
149 } | |
150 | |
151 inline static LmMessageNode *lm_message_node_find_xmlns(LmMessageNode *node, | |
152 const char *xmlns) | |
153 { | |
154 LmMessageNode *x; | |
155 const char *p; | |
156 | |
157 for (x = node->children ; x; x = x->next) { | |
158 if ((p = lm_message_node_get_attribute(x, "xmlns")) && !strcmp(p, xmlns)) | |
159 break; | |
160 } | |
161 return x; | |
162 } | |
163 | |
164 static time_t lm_message_node_get_timestamp(LmMessageNode *node) | |
165 { | |
166 LmMessageNode *x; | |
167 const char *p; | |
168 | |
169 x = lm_message_node_find_xmlns(node, NS_XMPP_DELAY); | |
170 if (x && (!strcmp(x->name, "delay")) && | |
171 (p = lm_message_node_get_attribute(x, "stamp")) != NULL) | |
172 return from_iso8601(p, 1); | |
173 x = lm_message_node_find_xmlns(node, NS_DELAY); | |
174 if (x && (p = lm_message_node_get_attribute(x, "stamp")) != NULL) | |
175 return from_iso8601(p, 1); | |
176 return 0; | |
177 } | |
178 | |
179 // lm_message_new_presence(status, recipient, message) | |
180 // Create an xmlnode with default presence attributes | |
181 // Note: the caller must free the node after use | |
182 static LmMessage *lm_message_new_presence(enum imstatus st, | |
183 const char *recipient, | |
184 const char *msg) | |
185 { | |
186 unsigned int prio; | |
187 LmMessage *x = lm_message_new(recipient, LM_MESSAGE_TYPE_PRESENCE); | |
188 | |
189 switch(st) { | |
190 case away: | |
191 case notavail: | |
192 case dontdisturb: | |
193 case freeforchat: | |
194 lm_message_node_add_child(x->node, "show", imstatus_showmap[st]); | |
195 break; | |
196 | |
197 case invisible: | |
198 lm_message_node_set_attribute(x->node, "type", "invisible"); | |
199 break; | |
200 | |
201 case offline: | |
202 lm_message_node_set_attribute(x->node, "type", "unavailable"); | |
203 break; | |
204 | |
205 default: | |
206 break; | |
207 } | |
208 | |
209 if (st == away || st == notavail) | |
210 prio = settings_opt_get_int("priority_away"); | |
211 else | |
212 prio = settings_opt_get_int("priority"); | |
213 | |
214 if (prio) { | |
215 char strprio[8]; | |
216 snprintf(strprio, 8, "%d", (int)prio); | |
217 lm_message_node_add_child(x->node, "priority", strprio); | |
218 } | |
219 | |
220 if (msg) | |
221 lm_message_node_add_child(x->node, "status", msg); | |
222 | |
223 return x; | |
224 } | |
225 | |
226 static const char *defaulterrormsg(guint code) | |
227 { | |
228 int i = 0; | |
229 | |
230 for (i = 0; xmpp_errors[i].code; ++i) { | |
231 if (xmpp_errors[i].code == code) | |
232 return xmpp_errors[i].meaning; | |
233 } | |
234 return NULL; | |
235 } | |
236 | |
237 // display_server_error(x) | |
238 // Display the error to the user | |
239 // x: error tag xmlnode pointer | |
240 void display_server_error(LmMessageNode *x) | |
241 { | |
242 const char *desc = NULL, *p=NULL, *s; | |
243 char *sdesc, *tmp; | |
244 int code = 0; | |
245 | |
246 if (!x) return; | |
247 | |
248 /* RFC3920: | |
249 * The <error/> element: | |
250 * o MUST contain a child element corresponding to one of the defined | |
251 * stanza error conditions specified below; this element MUST be | |
252 * qualified by the 'urn:ietf:params:xml:ns:xmpp-stanzas' namespace. | |
253 */ | |
254 if (x->children) | |
255 p = x->children->name; | |
256 if (p) | |
257 scr_LogPrint(LPRINT_LOGNORM, "Received error packet [%s]", p); | |
258 | |
259 // For backward compatibility | |
260 if ((s = lm_message_node_get_attribute(x, "code")) != NULL) { | |
261 code = atoi(s); | |
262 // Default message | |
263 desc = defaulterrormsg(code); | |
264 } | |
265 | |
266 // Error tag data is better, if available | |
267 s = lm_message_node_get_value(x); | |
268 if (s && *s) desc = s; | |
269 | |
270 // And sometimes there is a text message | |
271 s = lm_message_node_get_child_value(x, "text"); | |
272 | |
273 if (s && *s) desc = s; | |
274 | |
275 // If we still have no description, let's give up | |
276 if (!desc) | |
277 return; | |
278 | |
279 // Strip trailing newlines | |
280 sdesc = g_strdup(desc); | |
281 for (tmp = sdesc; *tmp; tmp++) ; | |
282 if (tmp > sdesc) | |
283 tmp--; | |
284 while (tmp >= sdesc && (*tmp == '\n' || *tmp == '\r')) | |
285 *tmp-- = '\0'; | |
286 | |
287 scr_LogPrint(LPRINT_LOGNORM, "Error code from server: %d %s", code, sdesc); | |
288 g_free(sdesc); | |
289 } | |
290 |