1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
15 #include "liblj/protocol.h"
16 #include "liblj/md5.h"
24 /* in a result, only one string is allocated,
25 * and the rest of the hash table is pointers within that string.
26 * we need to keep a pointer to that string around for when we free the
32 static inline gboolean
34 return !isalnum(c
) && c
!= '_';
38 lj_urlencode(const char *string
) {
44 char hextable
[] = { '0', '1', '2', '3', '4', '5', '6', '7',
45 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
47 if (string
== NULL
) return NULL
;
49 for (src
= string
; *src
!= 0; src
++)
50 if (needsescape(*src
)) escapecount
++;
52 newstr
= g_new(char, (src
-string
) - escapecount
+ (escapecount
* 3) + 1);
57 if (needsescape(*src
)) {
58 unsigned char c
= *src
;
60 *dest
++ = hextable
[c
>> 4];
61 *dest
++ = hextable
[c
& 0x0F];
73 lj_urldecode(const char *string
) {
79 if (string
== NULL
) return NULL
;
81 for (src
= string
; *src
!= 0; src
++) {
82 if (*src
== '%') { src
+=2; } /* FIXME: this isn't robust. should check
83 the next two chars for 0 */
87 newstr
= g_new(char, destlen
+ 1);
92 char h
= (char)toupper(src
[1]);
93 char l
= (char)toupper(src
[2]);
95 vh
= isalpha(h
) ? (10+(h
-'A')) : (h
-'0');
96 vl
= isalpha(l
) ? (10+(l
-'A')) : (l
-'0');
97 *dest
++ = ((vh
<<4)+vl
);
99 } else if (*src
== '+') {
111 /* retrieve a pointer to the current line, modifying src in place. */
113 get_line_inplace(char *src
, char **dest
) {
115 while (*src
!= 0 && *src
!= '\n')
127 lj_result_new(void) {
128 return g_new0(LJResult
, 1);
132 lj_result_new_from_response(const char *res
) {
140 /* shortcut the common error case. */
141 if (res
== NULL
|| *res
== 0)
144 /* make our own copy so we can modify it. */
145 origsrc
= src
= g_strdup(res
);
146 hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
, NULL
);
149 src
= get_line_inplace(src
, &key
);
151 src
= get_line_inplace(src
, &val
);
152 g_hash_table_insert(hash
, key
, val
);
156 if (read_keys
== 0) { /* error. */
158 g_hash_table_destroy(hash
);
162 result
= lj_result_new();
163 result
->string
= origsrc
;
169 lj_result_succeeded(LJResult
*result
) {
172 if (result
== NULL
) return FALSE
;
174 error
= lj_result_get(result
, "success");
175 if (error
== NULL
) return FALSE
;
177 return (g_ascii_strcasecmp(error
, "OK") == 0);
181 lj_request_add(LJRequest
*request
, const char *key
, const char *val
) {
182 g_hash_table_insert(request
->hash
, g_strdup(key
), g_strdup(val
));
185 lj_request_add_int(LJRequest
*request
, const char *key
, int val
) {
186 g_hash_table_insert(request
->hash
, g_strdup(key
), g_strdup_printf("%d", val
));
190 lj_request_new_without_auth(LJUser
*user
, const char *mode
) {
191 LJRequest
*request
= g_new0(LJRequest
, 1);
193 request
->user
= user
;
194 request
->hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
196 lj_request_add(request
, "mode", mode
);
198 lj_request_add_int(request
, "ver", user
->server
->protocolversion
);
204 lj_request_new(LJUser
*user
, const char *mode
) {
205 LJRequest
*request
= lj_request_new_without_auth(user
, mode
);
207 lj_request_add(request
, "user", user
->username
);
208 lj_md5_hash(user
->password
, buf
);
209 lj_request_add(request
, "hpassword", buf
);
214 lj_request_use_challenge(LJRequest
*request
, LJChallenge challenge
) {
219 /* make sure we're not passing a password. */
220 g_hash_table_remove(request
->hash
, "password");
221 g_hash_table_remove(request
->hash
, "hpassword");
223 lj_request_add(request
, "auth_method", "challenge");
224 lj_request_add(request
, "auth_challenge", challenge
);
225 lj_md5_hash(request
->user
->password
, passhash
);
226 chalpass
= g_strconcat(challenge
, passhash
, NULL
);
227 lj_md5_hash(chalpass
, fullhash
);
229 lj_request_add(request
, "auth_response", fullhash
);
233 lj_request_get_user(LJRequest
*request
) {
234 return request
->user
;
238 hash_append_str_encoded(gpointer key
, gpointer value
, gpointer data
) {
239 GString
*string
= data
;
240 gchar
*en_key
, *en_value
;
242 if (key
== NULL
|| value
== NULL
) return;
243 en_key
= lj_urlencode(key
);
244 en_value
= lj_urlencode(value
);
247 g_string_append_c(string
, '&');
248 g_string_append_printf(string
, "%s=%s", en_key
, en_value
);
255 lj_request_to_string(LJRequest
* request
) {
256 GString
*str
= g_string_sized_new(2048);
257 g_hash_table_foreach(request
->hash
, hash_append_str_encoded
, str
);
262 lj_request_free(LJRequest
*request
) {
263 g_hash_table_destroy(request
->hash
);
268 char *showfirst
[] = { "mode", "user", "password", "hpassword", "usejournal", "ver" };
270 hash_dump(gpointer key
, gpointer value
, gpointer data
) {
272 for (i
= 0; i
< SHOWCOUNT
; i
++)
273 if (g_ascii_strcasecmp((char*)key
, showfirst
[i
]) == 0)
275 g_print("\t%s: %s\n", (char*)key
, (char*)value
);
279 lj_request_dump(LJRequest
*request
) {
282 for (i
= 0; i
< SHOWCOUNT
; i
++) {
283 value
= g_hash_table_lookup(request
->hash
, showfirst
[i
]);
284 if (!value
) continue;
285 g_print("\t%s: %s\n", showfirst
[i
], value
);
287 g_hash_table_foreach(request
->hash
, hash_dump
, NULL
);
291 lj_result_get(LJResult
*result
, const char *key
) {
292 return g_hash_table_lookup(result
->hash
, key
);
296 lj_result_getf(LJResult
* result
, const char *key
, ...) {
301 g_vsnprintf(buf
, 100, key
, ap
);
303 return lj_result_get(result
, buf
);
307 lj_result_get_int(LJResult
*result
, const char *key
) {
309 val
= lj_result_get(result
, key
);
316 lj_result_getf_int(LJResult
* result
, const char *key
, ...) {
321 g_vsnprintf(buf
, 100, key
, ap
);
323 return lj_result_get_int(result
, buf
);
327 lj_result_free(LJResult
*result
) {
328 if (!result
) return; /* NULL result is the error result. */
329 g_free(result
->string
);
330 g_hash_table_destroy(result
->hash
);