comparison src/protocols/jabber/jutil.c @ 7014:67c4e9d39242

[gaim-migrate @ 7577] Here it is, the bulk of the new Jabber prpl. Left to do: - Implement registration - Implement password changing - Keep track of conversation threads (since I apparently have to) - Fix the bugs that always magically appear in code after I commit committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Mon, 29 Sep 2003 15:23:19 +0000
parents 988485669631
children 1930e3d00ecd
comparison
equal deleted inserted replaced
7013:859cafb6433f 7014:67c4e9d39242
1 /* -------------------------------------------------------------------------- 1 /*
2 * gaim - Jabber Protocol Plugin
2 * 3 *
3 * License 4 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com>
4 * 5 *
5 * The contents of this file are subject to the Jabber Open Source License 6 * This program is free software; you can redistribute it and/or modify
6 * Version 1.0 (the "JOSL"). You may not copy or use this file, in either 7 * it under the terms of the GNU General Public License as published by
7 * source code or executable form, except in compliance with the JOSL. You 8 * the Free Software Foundation; either version 2 of the License, or
8 * may obtain a copy of the JOSL at http://www.jabber.org/ or at 9 * (at your option) any later version.
9 * http://www.opensource.org/.
10 * 10 *
11 * Software distributed under the JOSL is distributed on an "AS IS" basis, 11 * This program is distributed in the hope that it will be useful,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * for the specific language governing rights and limitations under the 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * JOSL. 14 * GNU General Public License for more details.
15 * 15 *
16 * Copyrights 16 * You should have received a copy of the GNU General Public License
17 * 17 * along with this program; if not, write to the Free Software
18 * Portions created by or assigned to Jabber.com, Inc. are 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact
20 * information for Jabber.com, Inc. is available at http://www.jabber.com/.
21 * 19 *
22 * Portions Copyright (c) 1998-1999 Jeremie Miller. 20 */
23 * 21 #include "internal.h"
24 * Acknowledgements 22 #include "server.h"
25 *
26 * Special thanks to the Jabber Open Source Contributors for their
27 * suggestions and support of Jabber.
28 *
29 * Alternatively, the contents of this file may be used under the terms of the
30 * GNU General Public License Version 2 or later (the "GPL"), in which case
31 * the provisions of the GPL are applicable instead of those above. If you
32 * wish to allow use of your version of this file only under the terms of the
33 * GPL and not to allow others to use your version of this file under the JOSL,
34 * indicate your decision by deleting the provisions above and replace them
35 * with the notice and other provisions required by the GPL. If you do not
36 * delete the provisions above, a recipient may use your version of this file
37 * under either the JOSL or the GPL.
38 *
39 *
40 * --------------------------------------------------------------------------*/
41 23
42 #include "lib.h" 24 #include "presence.h"
25 #include "jutil.h"
43 26
44 #ifdef _WIN32 27 time_t str_to_time(const char *timestamp)
45 #include "win32dep.h" 28 {
29 struct tm t;
30 time_t retval = 0;
31 char buf[32];
32 char *c;
33 int tzoff = 0;
34
35 time(&retval);
36 localtime_r(&retval, &t);
37
38 snprintf(buf, sizeof(buf), "%s", timestamp);
39 c = buf;
40
41 /* 4 digit year */
42 if(!sscanf(c, "%04d", &t.tm_year)) return 0;
43 c+=4;
44 if(*c == '-')
45 c++;
46
47 t.tm_year -= 1900;
48
49 /* 2 digit month */
50 if(!sscanf(c, "%02d", &t.tm_mon)) return 0;
51 c+=2;
52 if(*c == '-')
53 c++;
54
55 t.tm_mon -= 1;
56
57 /* 2 digit day */
58 if(!sscanf(c, "%02d", &t.tm_mday)) return 0;
59 c+=2;
60 if(*c == 'T') { /* we have more than a date, keep going */
61 c++; /* skip the "T" */
62
63 /* 2 digit hour */
64 if(sscanf(c, "%02d:%02d:%02d", &t.tm_hour, &t.tm_min, &t.tm_sec)) {
65 int tzhrs, tzmins;
66 c+=8;
67 if(*c == '.') /* dealing with precision we don't care about */
68 c += 4;
69
70 if((*c == '+' || *c == '-') &&
71 sscanf(c+1, "%02d:%02d", &tzhrs, &tzmins)) {
72 tzoff = tzhrs*60*60 + tzmins*60;
73 if(*c == '+')
74 tzoff *= -1;
75 }
76
77 #ifdef HAVE_TM_GMTOFF
78 tzoff += t.tm_gmtoff;
79 #else
80 # ifdef HAVE_TIMEZONE
81 tzset(); /* making sure */
82 tzoff -= timezone;
83 # endif
46 #endif 84 #endif
85 }
86 }
87 retval = mktime(&t);
47 88
48 /* util for making presence packets */ 89 retval += tzoff;
49 xmlnode jutil_presnew(int type, char *to, char *status)
50 {
51 xmlnode pres;
52 90
53 pres = xmlnode_new_tag("presence"); 91 return retval;
54 switch(type)
55 {
56 case JPACKET__SUBSCRIBE:
57 xmlnode_put_attrib(pres,"type","subscribe");
58 break;
59 case JPACKET__UNSUBSCRIBE:
60 xmlnode_put_attrib(pres,"type","unsubscribe");
61 break;
62 case JPACKET__SUBSCRIBED:
63 xmlnode_put_attrib(pres,"type","subscribed");
64 break;
65 case JPACKET__UNSUBSCRIBED:
66 xmlnode_put_attrib(pres,"type","unsubscribed");
67 break;
68 case JPACKET__PROBE:
69 xmlnode_put_attrib(pres,"type","probe");
70 break;
71 case JPACKET__UNAVAILABLE:
72 xmlnode_put_attrib(pres,"type","unavailable");
73 break;
74 case JPACKET__INVISIBLE:
75 xmlnode_put_attrib(pres,"type","invisible");
76 break;
77 }
78 if(to != NULL)
79 xmlnode_put_attrib(pres,"to",to);
80 if(status != NULL)
81 xmlnode_insert_cdata(xmlnode_insert_tag(pres,"status"),status,strlen(status));
82
83 return pres;
84 } 92 }
85 93
86 /* util for making IQ packets */ 94 const char *jabber_get_state_string(int s) {
87 xmlnode jutil_iqnew(int type, char *ns) 95 switch(s) {
88 { 96 case JABBER_STATE_AWAY:
89 xmlnode iq; 97 return _("Away");
90 98 break;
91 iq = xmlnode_new_tag("iq"); 99 case JABBER_STATE_CHAT:
92 switch(type) 100 return _("Chatty");
93 { 101 break;
94 case JPACKET__GET: 102 case JABBER_STATE_XA:
95 xmlnode_put_attrib(iq,"type","get"); 103 return _("Extended Away");
96 break; 104 break;
97 case JPACKET__SET: 105 case JABBER_STATE_DND:
98 xmlnode_put_attrib(iq,"type","set"); 106 return _("Do Not Disturb");
99 break; 107 break;
100 case JPACKET__RESULT: 108 default:
101 xmlnode_put_attrib(iq,"type","result"); 109 return _("Available");
102 break; 110 break;
103 case JPACKET__ERROR: 111 }
104 xmlnode_put_attrib(iq,"type","error");
105 break;
106 }
107 xmlnode_put_attrib(xmlnode_insert_tag(iq,"query"),"xmlns",ns);
108
109 return iq;
110 } 112 }
111 113
112 /* util for making message packets */ 114 JabberID*
113 xmlnode jutil_msgnew(char *type, char *to, char *subj, char *body) 115 jabber_id_new(const char *str)
114 { 116 {
115 xmlnode msg; 117 char *at;
118 char *slash;
116 119
117 msg = xmlnode_new_tag("message"); 120 JabberID *jid;
118 xmlnode_put_attrib (msg, "type", type);
119 xmlnode_put_attrib (msg, "to", to);
120 121
121 if (subj) 122 if(!str)
122 { 123 return NULL;
123 xmlnode_insert_cdata (xmlnode_insert_tag (msg, "subject"), subj, strlen (subj));
124 }
125 124
126 xmlnode_insert_cdata (xmlnode_insert_tag (msg, "body"), body, strlen (body)); 125 jid = g_new0(JabberID, 1);
127 126
128 return msg; 127 at = strchr(str, '@');
128 slash = strchr(str, '/');
129
130 if(at) {
131 jid->node = g_strndup(str, at-str);
132 if(slash) {
133 jid->domain = g_strndup(at+1, slash-(at+1));
134 jid->resource = g_strdup(slash+1);
135 } else {
136 jid->domain = g_strdup(at+1);
137 }
138 } else {
139 if(slash) {
140 jid->domain = g_strndup(str, slash-str);
141 jid->resource = g_strdup(slash+1);
142 } else {
143 jid->domain = g_strdup(str);
144 }
145 }
146
147 return jid;
129 } 148 }
130 149
131 /* util for making stream packets */ 150 void
132 xmlnode jutil_header(char* xmlns, char* server) 151 jabber_id_free(JabberID *jid)
133 { 152 {
134 xmlnode result; 153 if(jid) {
135 if ((xmlns == NULL)||(server == NULL)) 154 if(jid->node)
136 return NULL; 155 g_free(jid->node);
137 result = xmlnode_new_tag("stream:stream"); 156 if(jid->domain)
138 xmlnode_put_attrib(result, "xmlns:stream", "http://etherx.jabber.org/streams"); 157 g_free(jid->domain);
139 xmlnode_put_attrib(result, "xmlns", xmlns); 158 if(jid->resource)
140 xmlnode_put_attrib(result, "to", server); 159 g_free(jid->resource);
141 160 g_free(jid);
142 return result; 161 }
143 } 162 }
144 163
145 /* returns the priority on a presence packet */ 164
146 int jutil_priority(xmlnode x) 165 const char *jabber_get_resource(const char *jid)
147 { 166 {
148 char *str; 167 char *slash;
149 int p;
150 168
151 if(x == NULL) 169 slash = strrchr(jid, '/');
152 return -1; 170 if(slash)
153 171 return slash+1;
154 if(xmlnode_get_attrib(x,"type") != NULL) 172 else
155 return -1; 173 return NULL;
156
157 x = xmlnode_get_tag(x,"priority");
158 if(x == NULL)
159 return 0;
160
161 str = xmlnode_get_data((x));
162 if(str == NULL)
163 return 0;
164
165 p = atoi(str);
166 if(p >= 0)
167 return p;
168 else
169 return 0;
170 } 174 }
171 175
172 void jutil_tofrom(xmlnode x) 176 char *jabber_get_bare_jid(const char *jid)
173 { 177 {
174 char *to, *from; 178 char *slash;
179 slash = strrchr(jid, '/');
175 180
176 to = xmlnode_get_attrib(x,"to"); 181 if(slash)
177 from = xmlnode_get_attrib(x,"from"); 182 return g_strndup(jid, slash - jid);
178 xmlnode_put_attrib(x,"from",to); 183 else
179 xmlnode_put_attrib(x,"to",from); 184 return g_strdup(jid);
180 } 185 }
181
182 xmlnode jutil_iqresult(xmlnode x)
183 {
184 xmlnode cur;
185
186 jutil_tofrom(x);
187
188 xmlnode_put_attrib(x,"type","result");
189
190 /* hide all children of the iq, they go back empty */
191 for(cur = xmlnode_get_firstchild(x); cur != NULL; cur = xmlnode_get_nextsibling(cur))
192 xmlnode_hide(cur);
193
194 return x;
195 }
196
197 char *jutil_timestamp(void)
198 {
199 time_t t;
200 struct tm *new_time;
201 static char timestamp[18];
202 int ret;
203
204 t = time(NULL);
205
206 if(t == (time_t)-1)
207 return NULL;
208 new_time = gmtime(&t);
209
210 ret = snprintf(timestamp, 18, "%d%02d%02dT%02d:%02d:%02d", 1900+new_time->tm_year,
211 new_time->tm_mon+1, new_time->tm_mday, new_time->tm_hour,
212 new_time->tm_min, new_time->tm_sec);
213
214 if(ret == -1)
215 return NULL;
216
217 return timestamp;
218 }
219
220 void jutil_error(xmlnode x, terror E)
221 {
222 xmlnode err;
223 char code[4];
224
225 xmlnode_put_attrib(x,"type","error");
226 err = xmlnode_insert_tag(x,"error");
227
228 snprintf(code,4,"%d",E.code);
229 xmlnode_put_attrib(err,"code",code);
230 if(E.msg != NULL)
231 xmlnode_insert_cdata(err,E.msg,strlen(E.msg));
232
233 jutil_tofrom(x);
234 }
235
236 void jutil_delay(xmlnode msg, char *reason)
237 {
238 xmlnode delay;
239
240 delay = xmlnode_insert_tag(msg,"x");
241 xmlnode_put_attrib(delay,"xmlns",NS_DELAY);
242 xmlnode_put_attrib(delay,"from",xmlnode_get_attrib(msg,"to"));
243 xmlnode_put_attrib(delay,"stamp",jutil_timestamp());
244 if(reason != NULL)
245 xmlnode_insert_cdata(delay,reason,strlen(reason));
246 }
247
248 #define KEYBUF 100
249
250 char *jutil_regkey(char *key, char *seed)
251 {
252 static char keydb[KEYBUF][41];
253 static char seeddb[KEYBUF][41];
254 static int last = -1;
255 char *str, strint[32];
256 int i;
257
258 /* blanket the keydb first time */
259 if(last == -1)
260 {
261 last = 0;
262 memset(&keydb,0,KEYBUF*41);
263 memset(&seeddb,0,KEYBUF*41);
264 srand(time(NULL));
265 }
266
267 /* creation phase */
268 if(key == NULL && seed != NULL)
269 {
270 /* create a random key hash and store it */
271 sprintf(strint,"%d",rand());
272 strcpy(keydb[last],shahash(strint));
273
274 /* store a hash for the seed associated w/ this key */
275 strcpy(seeddb[last],shahash(seed));
276
277 /* return it all */
278 str = keydb[last];
279 last++;
280 if(last == KEYBUF) last = 0;
281 return str;
282 }
283
284 /* validation phase */
285 str = shahash(seed);
286 for(i=0;i<KEYBUF;i++)
287 if(j_strcmp(keydb[i],key) == 0 && j_strcmp(seeddb[i],str) == 0)
288 {
289 seeddb[i][0] = '\0'; /* invalidate this key */
290 return keydb[i];
291 }
292
293 return NULL;
294 }
295