Mercurial > audlegacy
annotate Plugins/General/scrobbler/scrobbler.c @ 1340:eaa1b6342e75 trunk
[svn] - itemtag buffer was too short. e.g. 256 bytes could hold only 28 url encoded kanji characters.
author | yaz |
---|---|
date | Tue, 27 Jun 2006 23:14:47 -0700 |
parents | 8a2d526864c2 |
children |
rev | line source |
---|---|
688 | 1 #include <pthread.h> |
2 #include <limits.h> | |
3 #include <stdlib.h> | |
4 #include <string.h> | |
5 #include <stdarg.h> | |
6 #include <curl/curl.h> | |
7 #include <stdio.h> | |
8 #include "fmt.h" | |
9 #include "md5.h" | |
10 #include "queue.h" | |
11 #include "scrobbler.h" | |
12 #include "config.h" | |
13 #include <glib.h> | |
14 | |
15 #define SCROBBLER_HS_URL "http://post.audioscrobbler.com" | |
690
85fa136c9edf
[svn] - Change client id from XMMS-Scrobbler to Audacious (we now have our own ID)
nenolod
parents:
688
diff
changeset
|
16 #define SCROBBLER_CLI_ID "aud" |
688 | 17 #define SCROBBLER_HS_WAIT 1800 |
18 #define SCROBBLER_SB_WAIT 10 | |
19 #define SCROBBLER_VERSION "1.1" | |
690
85fa136c9edf
[svn] - Change client id from XMMS-Scrobbler to Audacious (we now have our own ID)
nenolod
parents:
688
diff
changeset
|
20 #define SCROBBLER_IMPLEMENTATION "0.1" /* This is the implementation, not the player version. */ |
1340
eaa1b6342e75
[svn] - itemtag buffer was too short. e.g. 256 bytes could hold only 28 url encoded kanji characters.
yaz
parents:
1239
diff
changeset
|
21 #define SCROBBLER_SB_MAXLEN 1024 |
688 | 22 #define CACHE_SIZE 1024 |
23 | |
24 /* Scrobblerbackend for xmms plugin, first draft */ | |
25 | |
26 static int sc_hs_status, | |
27 sc_hs_timeout, | |
28 sc_hs_errors, | |
29 sc_sb_errors, | |
30 sc_bad_users, | |
31 sc_submit_interval, | |
32 sc_submit_timeout, | |
33 sc_srv_res_size, | |
34 sc_giveup, | |
35 sc_major_error_present; | |
36 | |
37 static char *sc_submit_url, | |
38 *sc_username, | |
39 *sc_password, | |
40 *sc_challenge_hash, | |
41 sc_response_hash[33], | |
42 *sc_srv_res, | |
43 sc_curl_errbuf[CURL_ERROR_SIZE], | |
44 *sc_major_error; | |
45 | |
46 static void dump_queue(); | |
47 | |
48 /* Error functions */ | |
49 | |
50 static void sc_throw_error(char *errortxt) | |
51 { | |
52 sc_major_error_present = 1; | |
53 if(sc_major_error == NULL) | |
54 sc_major_error = strdup(errortxt); | |
55 | |
56 return; | |
57 } | |
58 | |
59 int sc_catch_error(void) | |
60 { | |
61 return sc_major_error_present; | |
62 } | |
63 | |
64 char *sc_fetch_error(void) | |
65 { | |
66 return sc_major_error; | |
67 } | |
68 | |
69 void sc_clear_error(void) | |
70 { | |
71 sc_major_error_present = 0; | |
72 if(sc_major_error != NULL) | |
73 free(sc_major_error); | |
74 sc_major_error = NULL; | |
75 | |
76 return; | |
77 } | |
78 | |
79 static size_t sc_store_res(void *ptr, size_t size, | |
80 size_t nmemb, | |
700
99382cddf771
[svn] Fixes for all warnings (except 3 spurious GCC 4.0 ones, upgrade to 4.1 if you see them) and a performance increase. By external contributor Diego "FlameEyes" Petteno (Gentoo).
chainsaw
parents:
690
diff
changeset
|
81 void *stream __attribute__((unused))) |
688 | 82 { |
83 int len = size * nmemb; | |
84 | |
85 sc_srv_res = realloc(sc_srv_res, sc_srv_res_size + len + 1); | |
86 memcpy(sc_srv_res + sc_srv_res_size, | |
87 ptr, len); | |
88 sc_srv_res_size += len; | |
89 return len; | |
90 } | |
91 | |
92 static void sc_free_res(void) | |
93 { | |
94 if(sc_srv_res != NULL) | |
95 free(sc_srv_res); | |
96 sc_srv_res = NULL; | |
97 sc_srv_res_size = 0; | |
98 } | |
99 | |
100 static int sc_parse_hs_res(void) | |
101 { | |
102 char *interval; | |
103 | |
104 if (!sc_srv_res_size) { | |
105 pdebug("No reply from server", DEBUG); | |
106 return -1; | |
107 } | |
108 *(sc_srv_res + sc_srv_res_size) = 0; | |
109 | |
110 if (!strncmp(sc_srv_res, "FAILED ", 7)) { | |
111 interval = strstr(sc_srv_res, "INTERVAL"); | |
112 if(!interval) { | |
113 pdebug("missing INTERVAL", DEBUG); | |
114 } | |
115 else | |
116 { | |
117 *(interval - 1) = 0; | |
118 sc_submit_interval = strtol(interval + 8, NULL, 10); | |
119 } | |
120 | |
121 /* Throwing a major error, just in case */ | |
122 /* sc_throw_error(fmt_vastr("%s", sc_srv_res)); | |
123 sc_hs_errors++; */ | |
124 pdebug(fmt_vastr("error: %s", sc_srv_res), DEBUG); | |
125 | |
126 return -1; | |
127 } | |
128 | |
129 if (!strncmp(sc_srv_res, "UPDATE ", 7)) { | |
130 interval = strstr(sc_srv_res, "INTERVAL"); | |
131 if(!interval) | |
132 { | |
133 pdebug("missing INTERVAL", DEBUG); | |
134 } | |
135 else | |
136 { | |
137 *(interval - 1) = 0; | |
138 sc_submit_interval = strtol(interval + 8, NULL, 10); | |
139 } | |
140 | |
141 sc_submit_url = strchr(strchr(sc_srv_res, '\n') + 1, '\n') + 1; | |
142 *(sc_submit_url - 1) = 0; | |
143 sc_submit_url = strdup(sc_submit_url); | |
144 sc_challenge_hash = strchr(sc_srv_res, '\n') + 1; | |
145 *(sc_challenge_hash - 1) = 0; | |
146 sc_challenge_hash = strdup(sc_challenge_hash); | |
147 | |
148 /* Throwing major error. Need to alert client to update. */ | |
149 sc_throw_error(fmt_vastr("Please update Audacious.\n" | |
150 "Update available at: http://audacious-media-player.org")); | |
151 pdebug(fmt_vastr("update client: %s", sc_srv_res + 7), DEBUG); | |
152 | |
153 /* | |
154 * Russ isn't clear on whether we can submit with a not-updated | |
155 * client. Neither is RJ. I use what we did before. | |
156 */ | |
157 sc_giveup = -1; | |
158 return -1; | |
159 } | |
160 if (!strncmp(sc_srv_res, "UPTODATE\n", 9)) { | |
161 sc_bad_users = 0; | |
162 | |
163 interval = strstr(sc_srv_res, "INTERVAL"); | |
164 if (!interval) { | |
165 pdebug("missing INTERVAL", DEBUG); | |
166 /* | |
167 * This is probably a bad thing, but Russ seems to | |
168 * think its OK to assume that an UPTODATE response | |
169 * may not have an INTERVAL... We return -1 anyway. | |
170 */ | |
171 return -1; | |
172 } | |
173 else | |
174 { | |
175 *(interval - 1) = 0; | |
176 sc_submit_interval = strtol(interval + 8, NULL, 10); | |
177 } | |
178 | |
179 sc_submit_url = strchr(strchr(sc_srv_res, '\n') + 1, '\n') + 1; | |
180 *(sc_submit_url - 1) = 0; | |
181 sc_submit_url = strdup(sc_submit_url); | |
182 sc_challenge_hash = strchr(sc_srv_res, '\n') + 1; | |
183 *(sc_challenge_hash - 1) = 0; | |
184 sc_challenge_hash = strdup(sc_challenge_hash); | |
185 | |
186 return 0; | |
187 } | |
188 if(!strncmp(sc_srv_res, "BADUSER", 7)) { | |
189 /* Throwing major error. */ | |
190 sc_throw_error("Incorrect username/password.\n" | |
191 "Please fix in configuration."); | |
192 pdebug("incorrect username/password", DEBUG); | |
193 | |
194 interval = strstr(sc_srv_res, "INTERVAL"); | |
195 if(!interval) | |
196 { | |
197 pdebug("missing INTERVAL", DEBUG); | |
198 } | |
199 else | |
200 { | |
201 *(interval - 1) = 0; | |
202 sc_submit_interval = strtol(interval + 8, NULL, 10); | |
203 } | |
204 | |
205 return -1; | |
206 } | |
207 | |
208 pdebug(fmt_vastr("unknown server-reply '%s'", sc_srv_res), DEBUG); | |
209 return -1; | |
210 } | |
211 | |
212 static void hexify(char *pass, int len) | |
213 { | |
214 char *bp = sc_response_hash; | |
215 char hexchars[] = "0123456789abcdef"; | |
216 int i; | |
217 | |
218 memset(sc_response_hash, 0, sizeof(sc_response_hash)); | |
219 | |
220 for(i = 0; i < len; i++) { | |
221 *(bp++) = hexchars[(pass[i] >> 4) & 0x0f]; | |
222 *(bp++) = hexchars[pass[i] & 0x0f]; | |
223 } | |
224 *bp = 0; | |
225 | |
226 return; | |
227 } | |
228 | |
229 static int sc_handshake(void) | |
230 { | |
231 int status; | |
232 char buf[4096]; | |
233 CURL *curl; | |
234 | |
235 snprintf(buf, sizeof(buf), "%s/?hs=true&p=%s&c=%s&v=%s&u=%s", | |
236 SCROBBLER_HS_URL, SCROBBLER_VERSION, | |
690
85fa136c9edf
[svn] - Change client id from XMMS-Scrobbler to Audacious (we now have our own ID)
nenolod
parents:
688
diff
changeset
|
237 SCROBBLER_CLI_ID, SCROBBLER_IMPLEMENTATION, sc_username); |
688 | 238 |
239 curl = curl_easy_init(); | |
240 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); | |
241 curl_easy_setopt(curl, CURLOPT_URL, buf); | |
242 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, | |
243 sc_store_res); | |
244 memset(sc_curl_errbuf, 0, sizeof(sc_curl_errbuf)); | |
245 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, sc_curl_errbuf); | |
246 curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | |
247 status = curl_easy_perform(curl); | |
248 curl_easy_cleanup(curl); | |
249 | |
250 sc_hs_timeout = time(NULL) + SCROBBLER_HS_WAIT; | |
251 | |
252 if (status) { | |
253 pdebug(sc_curl_errbuf, DEBUG); | |
254 sc_hs_errors++; | |
255 sc_free_res(); | |
256 return -1; | |
257 } | |
258 | |
259 if (sc_parse_hs_res()) { | |
260 sc_hs_errors++; | |
261 sc_free_res(); | |
262 return -1; | |
263 } | |
264 | |
265 if (sc_challenge_hash != NULL) { | |
266 md5_state_t md5state; | |
267 unsigned char md5pword[16]; | |
268 | |
269 md5_init(&md5state); | |
270 /*pdebug(fmt_vastr("Pass Hash: %s", sc_password), DEBUG);*/ | |
271 md5_append(&md5state, (unsigned const char *)sc_password, | |
272 strlen(sc_password)); | |
273 /*pdebug(fmt_vastr("Challenge Hash: %s", sc_challenge_hash), DEBUG);*/ | |
274 md5_append(&md5state, (unsigned const char *)sc_challenge_hash, | |
275 strlen(sc_challenge_hash)); | |
276 md5_finish(&md5state, md5pword); | |
700
99382cddf771
[svn] Fixes for all warnings (except 3 spurious GCC 4.0 ones, upgrade to 4.1 if you see them) and a performance increase. By external contributor Diego "FlameEyes" Petteno (Gentoo).
chainsaw
parents:
690
diff
changeset
|
277 hexify((char*)md5pword, sizeof(md5pword)); |
688 | 278 /*pdebug(fmt_vastr("Response Hash: %s", sc_response_hash), DEBUG);*/ |
279 } | |
280 | |
281 sc_hs_errors = 0; | |
282 sc_hs_status = 1; | |
283 | |
284 sc_free_res(); | |
285 | |
286 pdebug(fmt_vastr("submiturl: %s - interval: %d", | |
287 sc_submit_url, sc_submit_interval), DEBUG); | |
288 | |
289 return 0; | |
290 } | |
291 | |
292 static int sc_parse_sb_res(void) | |
293 { | |
294 char *ch, *ch2; | |
295 | |
296 if (!sc_srv_res_size) { | |
297 pdebug("No response from server", DEBUG); | |
298 return -1; | |
299 } | |
300 *(sc_srv_res + sc_srv_res_size) = 0; | |
301 | |
302 if (!strncmp(sc_srv_res, "OK", 2)) { | |
303 if ((ch = strstr(sc_srv_res, "INTERVAL"))) { | |
304 sc_submit_interval = strtol(ch + 8, NULL, 10); | |
305 pdebug(fmt_vastr("got new interval: %d", | |
306 sc_submit_interval), DEBUG); | |
307 } | |
308 | |
309 pdebug(fmt_vastr("submission ok: %s", sc_srv_res), DEBUG); | |
310 | |
311 return 0; | |
312 } | |
313 | |
314 if (!strncmp(sc_srv_res, "BADAUTH", 7)) { | |
315 if ((ch = strstr(sc_srv_res, "INTERVAL"))) { | |
316 sc_submit_interval = strtol(ch + 8, NULL, 10); | |
317 pdebug(fmt_vastr("got new interval: %d", | |
318 sc_submit_interval), DEBUG); | |
319 } | |
320 | |
321 pdebug("incorrect username/password", DEBUG); | |
322 | |
323 sc_giveup = 0; | |
324 | |
325 /* | |
326 * We obviously aren't authenticated. The server might have | |
327 * lost our handshake status though, so let's try | |
328 * re-handshaking... This might not be proper. | |
329 * (we don't give up) | |
330 */ | |
331 sc_hs_status = 0; | |
332 | |
333 if(sc_challenge_hash != NULL) | |
334 free(sc_challenge_hash); | |
335 if(sc_submit_url != NULL) | |
336 free(sc_submit_url); | |
337 | |
338 sc_challenge_hash = sc_submit_url = NULL; | |
339 sc_bad_users++; | |
340 | |
341 if(sc_bad_users > 2) | |
342 { | |
343 pdebug("3 BADAUTH returns on submission. Halting " | |
344 "submissions until login fixed.", DEBUG) | |
345 sc_throw_error("Incorrect username/password.\n" | |
346 "Please fix in configuration."); | |
347 } | |
348 | |
349 return -1; | |
350 } | |
351 | |
352 if (!strncmp(sc_srv_res, "FAILED", 6)) { | |
353 if ((ch = strstr(sc_srv_res, "INTERVAL"))) { | |
354 sc_submit_interval = strtol(ch + 8, NULL, 10); | |
355 pdebug(fmt_vastr("got new interval: %d", | |
356 sc_submit_interval), DEBUG); | |
357 } | |
358 | |
359 /* This could be important. (Such as FAILED - Get new plugin) */ | |
360 /*sc_throw_error(fmt_vastr("%s", sc_srv_res));*/ | |
361 | |
362 pdebug(sc_srv_res, DEBUG); | |
363 | |
364 return -1; | |
365 } | |
366 | |
367 if (!strncmp(sc_srv_res, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">", 50)) { | |
368 ch = strstr(sc_srv_res, "<TITLE>") + 7; | |
369 ch2 = strstr(sc_srv_res, "</TITLE>"); | |
370 *ch2 = '\0'; | |
371 | |
372 pdebug(fmt_vastr("HTTP Error (%d): '%s'", | |
373 atoi(ch), ch + 4), DEBUG); | |
374 *ch2 = '<'; | |
375 | |
376 return -1; | |
377 } | |
378 | |
379 pdebug(fmt_vastr("unknown server-reply %s", sc_srv_res), DEBUG); | |
380 | |
381 return -1; | |
382 } | |
383 | |
384 static gchar *sc_itemtag(char c, int n, char *str) | |
385 { | |
1340
eaa1b6342e75
[svn] - itemtag buffer was too short. e.g. 256 bytes could hold only 28 url encoded kanji characters.
yaz
parents:
1239
diff
changeset
|
386 static char buf[SCROBBLER_SB_MAXLEN]; |
eaa1b6342e75
[svn] - itemtag buffer was too short. e.g. 256 bytes could hold only 28 url encoded kanji characters.
yaz
parents:
1239
diff
changeset
|
387 snprintf(buf, SCROBBLER_SB_MAXLEN, "&%c[%d]=%s", c, n, str); |
688 | 388 return buf; |
389 } | |
390 | |
391 #define cfa(f, l, n, v) \ | |
392 curl_formadd(f, l, CURLFORM_COPYNAME, n, \ | |
393 CURLFORM_PTRCONTENTS, v, CURLFORM_END) | |
394 | |
395 static int sc_generateentry(GString *submission) | |
396 { | |
397 int i; | |
398 item_t *item; | |
399 | |
400 i = 0; | |
401 #ifdef ALLOW_MULTIPLE | |
402 q_peekall(1); | |
403 while ((item = q_peekall(0)) && i < 10) { | |
404 #else | |
405 item = q_peek(); | |
406 #endif | |
407 if (!item) | |
408 return i; | |
409 | |
410 g_string_append(submission,sc_itemtag('a',i,I_ARTIST(item))); | |
411 g_string_append(submission,sc_itemtag('t',i,I_TITLE(item))); | |
412 g_string_append(submission,sc_itemtag('l',i,I_LEN(item))); | |
413 g_string_append(submission,sc_itemtag('i',i,I_TIME(item))); | |
414 g_string_append(submission,sc_itemtag('m',i,I_MB(item))); | |
415 g_string_append(submission,sc_itemtag('b',i,I_ALBUM(item))); | |
416 | |
417 pdebug(fmt_vastr("a[%d]=%s t[%d]=%s l[%d]=%s i[%d]=%s m[%d]=%s b[%d]=%s", | |
418 i, I_ARTIST(item), | |
419 i, I_TITLE(item), | |
420 i, I_LEN(item), | |
421 i, I_TIME(item), | |
422 i, I_MB(item), | |
423 i, I_ALBUM(item)), DEBUG); | |
424 #ifdef ALLOW_MULTIPLE | |
425 i++; | |
426 } | |
427 #endif | |
428 | |
429 return i; | |
430 } | |
431 | |
432 static int sc_submitentry(gchar *entry) | |
433 { | |
434 CURL *curl; | |
435 /* struct HttpPost *post = NULL , *last = NULL; */ | |
436 int status; | |
437 GString *submission; | |
438 | |
439 curl = curl_easy_init(); | |
440 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); | |
441 curl_easy_setopt(curl, CURLOPT_URL, sc_submit_url); | |
442 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, | |
443 sc_store_res); | |
444 curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT); | |
445 curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | |
446 /*cfa(&post, &last, "debug", "failed");*/ | |
447 | |
448 /*pdebug(fmt_vastr("Username: %s", sc_username), DEBUG);*/ | |
449 submission = g_string_new("u="); | |
450 g_string_append(submission,(gchar *)sc_username); | |
451 | |
452 /*pdebug(fmt_vastr("Response Hash: %s", sc_response_hash), DEBUG);*/ | |
453 g_string_append(submission,"&s="); | |
454 g_string_append(submission,(gchar *)sc_response_hash); | |
455 | |
456 g_string_append(submission, entry); | |
457 | |
458 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (char *)submission->str); | |
459 memset(sc_curl_errbuf, 0, sizeof(sc_curl_errbuf)); | |
460 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, sc_curl_errbuf); | |
461 | |
462 /* | |
463 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); | |
464 curl_easy_setopt(curl, CURLOPT_TIMEOUT, SCROBBLER_SB_WAIT); | |
465 */ | |
466 | |
467 status = curl_easy_perform(curl); | |
468 | |
469 curl_easy_cleanup(curl); | |
470 | |
471 g_string_free(submission,TRUE); | |
472 | |
473 if (status) { | |
474 pdebug(sc_curl_errbuf, DEBUG); | |
475 sc_sb_errors++; | |
476 sc_free_res(); | |
477 return -1; | |
478 } | |
479 | |
480 if (sc_parse_sb_res()) { | |
481 sc_sb_errors++; | |
482 sc_free_res(); | |
483 pdebug(fmt_vastr("Retrying in %d secs, %d elements in queue", | |
484 sc_submit_interval, q_len()), DEBUG); | |
485 return -1; | |
486 } | |
487 sc_free_res(); | |
488 return 0; | |
489 } | |
490 | |
491 static void sc_handlequeue(GMutex *mutex) | |
492 { | |
493 GString *submitentry; | |
494 int nsubmit; | |
495 int wait; | |
496 | |
497 if(sc_submit_timeout < time(NULL) && sc_bad_users < 3) | |
498 { | |
499 submitentry = g_string_new(""); | |
500 | |
501 g_mutex_lock(mutex); | |
502 | |
503 nsubmit = sc_generateentry(submitentry); | |
504 | |
505 g_mutex_unlock(mutex); | |
506 | |
507 if (nsubmit > 0) | |
508 { | |
509 pdebug(fmt_vastr("Number submitting: %d", nsubmit), DEBUG); | |
510 pdebug(fmt_vastr("Submission: %s", submitentry->str), DEBUG); | |
511 | |
512 if(!sc_submitentry(submitentry->str)) | |
513 { | |
514 g_mutex_lock(mutex); | |
515 | |
516 #ifdef ALLOW_MULTIPLE | |
517 q_free(); | |
518 #else | |
519 q_get(); | |
520 #endif | |
521 /* | |
522 * This should make sure that the queue doesn't | |
523 * get submitted multiple times on a nasty | |
524 * segfault... | |
525 */ | |
526 dump_queue(); | |
527 | |
528 g_mutex_unlock(mutex); | |
529 | |
530 sc_sb_errors = 0; | |
531 } | |
532 if(sc_sb_errors) | |
533 { | |
534 if(sc_sb_errors < 5) | |
535 /* Retry after 1 min */ | |
536 wait = 60; | |
537 else | |
538 wait = /* sc_submit_interval + */ | |
539 ( ((sc_sb_errors - 5) < 7) ? | |
540 (60 << (sc_sb_errors-5)) : | |
541 7200 ); | |
542 | |
543 sc_submit_timeout = time(NULL) + wait; | |
544 | |
545 pdebug(fmt_vastr("Error while submitting. " | |
546 "Retrying after %d seconds.", wait), | |
547 DEBUG); | |
548 } | |
549 } | |
550 | |
551 g_string_free(submitentry, TRUE); | |
552 } | |
553 } | |
554 | |
555 static void read_cache(void) | |
556 { | |
557 FILE *fd; | |
1028
872e802cb1c0
[svn] - Use g_get_home_dir() instead of getenv ugliness here.
nenolod
parents:
813
diff
changeset
|
558 char buf[PATH_MAX], *cache = NULL, *ptr1, *ptr2; |
688 | 559 int cachesize, written, i = 0; |
560 item_t *item; | |
561 | |
562 cachesize = written = 0; | |
563 | |
1028
872e802cb1c0
[svn] - Use g_get_home_dir() instead of getenv ugliness here.
nenolod
parents:
813
diff
changeset
|
564 snprintf(buf, sizeof(buf), "%s/.audacious/scrobblerqueue.txt", g_get_home_dir()); |
688 | 565 |
566 if (!(fd = fopen(buf, "r"))) | |
567 return; | |
568 pdebug(fmt_vastr("Opening %s", buf), DEBUG); | |
569 while(!feof(fd)) | |
570 { | |
571 cachesize += CACHE_SIZE; | |
572 cache = realloc(cache, cachesize + 1); | |
573 written += fread(cache + written, 1, CACHE_SIZE, fd); | |
574 cache[written] = '\0'; | |
575 } | |
576 fclose(fd); | |
577 ptr1 = cache; | |
578 while(ptr1 < cache + written - 1) | |
579 { | |
580 char *artist, *title, *len, *time, *album, *mb; | |
581 | |
582 pdebug("Pushed:", DEBUG); | |
583 ptr2 = strchr(ptr1, ' '); | |
584 artist = calloc(1, ptr2 - ptr1 + 1); | |
585 strncpy(artist, ptr1, ptr2 - ptr1); | |
586 ptr1 = ptr2 + 1; | |
587 ptr2 = strchr(ptr1, ' '); | |
588 title = calloc(1, ptr2 - ptr1 + 1); | |
589 strncpy(title, ptr1, ptr2 - ptr1); | |
590 ptr1 = ptr2 + 1; | |
591 ptr2 = strchr(ptr1, ' '); | |
592 len = calloc(1, ptr2 - ptr1 + 1); | |
593 strncpy(len, ptr1, ptr2 - ptr1); | |
594 ptr1 = ptr2 + 1; | |
595 ptr2 = strchr(ptr1, ' '); | |
596 time = calloc(1, ptr2 - ptr1 + 1); | |
597 strncpy(time, ptr1, ptr2 - ptr1); | |
598 ptr1 = ptr2 + 1; | |
599 ptr2 = strchr(ptr1, ' '); | |
600 album = calloc(1, ptr2 - ptr1 + 1); | |
601 strncpy(album, ptr1, ptr2 - ptr1); | |
602 ptr1 = ptr2 + 1; | |
603 ptr2 = strchr(ptr1, '\n'); | |
604 if(ptr2 != NULL) | |
605 *ptr2 = '\0'; | |
606 mb = calloc(1, strlen(ptr1) + 1); | |
607 strncpy(mb, ptr1, strlen(ptr1)); | |
608 if(ptr2 != NULL) | |
609 *ptr2 = '\n'; | |
610 /* Why is our save printing out CR/LF? */ | |
611 ptr1 = ptr2 + 1; | |
612 | |
613 item = q_put2(artist, title, len, time, album, mb); | |
614 pdebug(fmt_vastr("a[%d]=%s t[%d]=%s l[%d]=%s i[%d]=%s m[%d]=%s b[%d]=%s", | |
615 i, I_ARTIST(item), | |
616 i, I_TITLE(item), | |
617 i, I_LEN(item), | |
618 i, I_TIME(item), | |
619 i, I_MB(item), | |
620 i, I_ALBUM(item)), DEBUG); | |
621 free(artist); | |
622 free(title); | |
623 free(len); | |
624 free(time); | |
625 free(album); | |
626 free(mb); | |
627 | |
628 i++; | |
629 } | |
630 pdebug("Done loading cache.", DEBUG); | |
813
c8cf439179b8
[svn] - Fix a ton and a half of memory leaks, via the wonderful Leonardo Boshell <leonardop -at- gentoo.org>.
nenolod
parents:
700
diff
changeset
|
631 free(cache); |
688 | 632 } |
633 | |
634 static void dump_queue(void) | |
635 { | |
636 FILE *fd; | |
637 item_t *item; | |
638 char *home, buf[PATH_MAX]; | |
639 | |
640 /*pdebug("Entering dump_queue();", DEBUG);*/ | |
641 | |
642 if (!(home = getenv("HOME"))) | |
643 { | |
644 pdebug("No HOME directory found. Cannot dump queue.", DEBUG); | |
645 return; | |
646 } | |
647 | |
648 snprintf(buf, sizeof(buf), "%s/.audacious/scrobblerqueue.txt", home); | |
649 | |
650 if (!(fd = fopen(buf, "w"))) | |
651 { | |
652 pdebug(fmt_vastr("Failure opening %s", buf), DEBUG); | |
653 return; | |
654 } | |
655 | |
656 pdebug(fmt_vastr("Opening %s", buf), DEBUG); | |
657 | |
658 q_peekall(1); | |
659 | |
660 while ((item = q_peekall(0))) { | |
661 fprintf(fd, "%s %s %s %s %s %s\n", | |
662 I_ARTIST(item), | |
663 I_TITLE(item), | |
664 I_LEN(item), | |
665 I_TIME(item), | |
666 I_ALBUM(item), | |
667 I_MB(item)); | |
668 } | |
669 | |
670 fclose(fd); | |
671 } | |
672 | |
673 /* This was made public */ | |
674 | |
675 void sc_cleaner(void) | |
676 { | |
677 if(sc_submit_url != NULL) | |
678 free(sc_submit_url); | |
679 if(sc_username != NULL) | |
680 free(sc_username); | |
681 if(sc_password != NULL) | |
682 free(sc_password); | |
683 if(sc_challenge_hash != NULL) | |
684 free(sc_challenge_hash); | |
685 if(sc_srv_res != NULL) | |
686 free(sc_srv_res); | |
687 if(sc_major_error != NULL) | |
688 free(sc_major_error); | |
689 dump_queue(); | |
690 q_free(); | |
691 pdebug("scrobbler shutting down", DEBUG); | |
692 } | |
693 | |
694 static void sc_checkhandshake(void) | |
695 { | |
696 int wait; | |
697 | |
698 if (sc_hs_status) | |
699 return; | |
700 if (sc_hs_timeout < time(NULL)) | |
701 { | |
702 sc_handshake(); | |
703 | |
704 if(sc_hs_errors) | |
705 { | |
706 if(sc_hs_errors < 5) | |
707 /* Retry after 60 seconds */ | |
708 wait = 60; | |
709 else | |
710 wait = /* sc_submit_interval + */ | |
711 ( ((sc_hs_errors - 5) < 7) ? | |
712 (60 << (sc_hs_errors-5)) : | |
713 7200 ); | |
714 sc_hs_timeout = time(NULL) + wait; | |
715 pdebug(fmt_vastr("Error while handshaking. Retrying " | |
716 "after %d seconds.", wait), DEBUG); | |
717 } | |
718 } | |
719 } | |
720 | |
721 /**** Public *****/ | |
722 | |
723 /* Called at session startup*/ | |
724 | |
725 void sc_init(char *uname, char *pwd) | |
726 { | |
727 sc_hs_status = sc_hs_timeout = sc_hs_errors = sc_submit_timeout = | |
728 sc_srv_res_size = sc_giveup = sc_major_error_present = | |
729 sc_bad_users = sc_sb_errors = 0; | |
730 sc_submit_interval = 100; | |
731 | |
732 sc_submit_url = sc_username = sc_password = sc_srv_res = | |
733 sc_challenge_hash = sc_major_error = NULL; | |
734 sc_username = strdup(uname); | |
735 sc_password = strdup(pwd); | |
736 read_cache(); | |
737 pdebug("scrobbler starting up", DEBUG); | |
738 } | |
739 | |
1236
fc478bfe6fe6
[svn] - disconnect the scrobbler client from metatag logically
nenolod
parents:
1028
diff
changeset
|
740 void sc_addentry(GMutex *mutex, TitleInput *tuple, int len) |
688 | 741 { |
742 g_mutex_lock(mutex); | |
1236
fc478bfe6fe6
[svn] - disconnect the scrobbler client from metatag logically
nenolod
parents:
1028
diff
changeset
|
743 q_put(tuple, len); |
688 | 744 /* |
745 * This will help make sure the queue will be saved on a nasty | |
746 * segfault... | |
747 */ | |
748 dump_queue(); | |
749 g_mutex_unlock(mutex); | |
750 } | |
751 | |
752 /* Call periodically from the plugin */ | |
753 int sc_idle(GMutex *mutex) | |
754 { | |
755 sc_checkhandshake(); | |
756 if (sc_hs_status) | |
757 sc_handlequeue(mutex); | |
758 | |
759 return sc_giveup; | |
760 } |