cddb.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. #include <ctype.h>
  13. char *server = "freedb.freedb.org";
  14. int debug;
  15. #define DPRINT if(debug)fprint
  16. int tflag;
  17. int Tflag;
  18. typedef struct Track Track;
  19. struct Track {
  20. int n;
  21. char *title;
  22. };
  23. enum {
  24. MTRACK = 64,
  25. };
  26. typedef struct Toc Toc;
  27. struct Toc {
  28. uint32_t diskid;
  29. int ntrack;
  30. char *title;
  31. Track track[MTRACK];
  32. };
  33. void*
  34. emalloc(uint n)
  35. {
  36. void *p;
  37. p = malloc(n);
  38. if(p == nil)
  39. sysfatal("can't malloc: %r");
  40. memset(p, 0, n);
  41. return p;
  42. }
  43. char*
  44. estrdup(char *s)
  45. {
  46. char *t;
  47. t = emalloc(strlen(s)+1);
  48. strcpy(t, s);
  49. return t;
  50. }
  51. static void
  52. dumpcddb(Toc *t)
  53. {
  54. int i, n, s;
  55. print("title %s\n", t->title);
  56. for(i=0; i<t->ntrack; i++){
  57. if(tflag){
  58. n = t->track[i+1].n;
  59. if(i == t->ntrack-1)
  60. n *= 75;
  61. s = (n - t->track[i].n)/75;
  62. print("%d\t%s\t%d:%2.2d\n", i+1, t->track[i].title, s/60, s%60);
  63. }
  64. else
  65. print("%d\t%s\n", i+1, t->track[i].title);
  66. }
  67. if(Tflag){
  68. s = t->track[i].n;
  69. print("Total time: %d:%2.2d\n", s/60, s%60);
  70. }
  71. }
  72. char*
  73. append(char *a, char *b)
  74. {
  75. char *c;
  76. c = emalloc(strlen(a)+strlen(b)+1);
  77. strcpy(c, a);
  78. strcat(c, b);
  79. return c;
  80. }
  81. static int
  82. cddbfilltoc(Toc *t)
  83. {
  84. int fd;
  85. int i;
  86. char *p, *q;
  87. Biobuf bin;
  88. char *f[10];
  89. int nf;
  90. char *id, *categ;
  91. fd = dial(netmkaddr(server, "tcp", "888"), 0, 0, 0);
  92. if(fd < 0) {
  93. fprint(2, "%s: %s: cannot dial: %r\n", argv0, server);
  94. return -1;
  95. }
  96. Binit(&bin, fd, OREAD);
  97. if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) {
  98. died:
  99. close(fd);
  100. Bterm(&bin);
  101. fprint(2, "%s: error talking to cddb server %s\n",
  102. argv0, server);
  103. if(p) {
  104. p[Blinelen(&bin)-1] = 0;
  105. fprint(2, "%s: server says: %s\n", argv0, p);
  106. }
  107. return -1;
  108. }
  109. fprint(fd, "cddb hello gre plan9 9cd 1.0\r\n");
  110. if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
  111. goto died;
  112. /*
  113. * Protocol level 6 is the same as level 5 except that
  114. * the character set is now UTF-8 instead of ISO-8859-1.
  115. */
  116. fprint(fd, "proto 6\r\n");
  117. DPRINT(2, "proto 6\r\n");
  118. if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
  119. goto died;
  120. p[Blinelen(&bin)-1] = 0;
  121. DPRINT(2, "cddb: %s\n", p);
  122. fprint(fd, "cddb query %8.8lux %d", t->diskid, t->ntrack);
  123. DPRINT(2, "cddb query %8.8lux %d", t->diskid, t->ntrack);
  124. for(i=0; i<t->ntrack; i++) {
  125. fprint(fd, " %d", t->track[i].n);
  126. DPRINT(2, " %d", t->track[i].n);
  127. }
  128. fprint(fd, " %d\r\n", t->track[t->ntrack].n);
  129. DPRINT(2, " %d\r\n", t->track[t->ntrack].n);
  130. if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
  131. goto died;
  132. p[Blinelen(&bin)-1] = 0;
  133. DPRINT(2, "cddb: %s\n", p);
  134. nf = tokenize(p, f, nelem(f));
  135. if(nf < 1)
  136. goto died;
  137. switch(atoi(f[0])) {
  138. case 200: /* exact match */
  139. if(nf < 3)
  140. goto died;
  141. categ = f[1];
  142. id = f[2];
  143. break;
  144. case 210: /* exact matches */
  145. case 211: /* close matches */
  146. if((p = Brdline(&bin, '\n')) == nil)
  147. goto died;
  148. if(p[0] == '.') /* no close matches? */
  149. goto died;
  150. p[Blinelen(&bin)-1] = '\0';
  151. /* accept first match */
  152. nf = tokenize(p, f, nelem(f));
  153. if(nf < 2)
  154. goto died;
  155. categ = f[0];
  156. id = f[1];
  157. /* snarf rest of buffer */
  158. while(p[0] != '.') {
  159. if((p = Brdline(&bin, '\n')) == nil)
  160. goto died;
  161. p[Blinelen(&bin)-1] = '\0';
  162. DPRINT(2, "cddb: %s\n", p);
  163. }
  164. break;
  165. case 202: /* no match */
  166. default:
  167. goto died;
  168. }
  169. t->title = "";
  170. for(i=0; i<t->ntrack; i++)
  171. t->track[i].title = "";
  172. /* fetch results for this cd */
  173. fprint(fd, "cddb read %s %s\r\n", categ, id);
  174. do {
  175. if((p = Brdline(&bin, '\n')) == nil)
  176. goto died;
  177. q = p+Blinelen(&bin)-1;
  178. while(isspace(*q))
  179. *q-- = 0;
  180. DPRINT(2, "cddb %s\n", p);
  181. if(strncmp(p, "DTITLE=", 7) == 0)
  182. t->title = append(t->title, p+7);
  183. else if(strncmp(p, "TTITLE", 6) == 0 && isdigit(p[6])) {
  184. i = atoi(p+6);
  185. if(i < t->ntrack) {
  186. p += 6;
  187. while(isdigit(*p))
  188. p++;
  189. if(*p == '=')
  190. p++;
  191. t->track[i].title = append(t->track[i].title, estrdup(p));
  192. }
  193. }
  194. } while(*p != '.');
  195. fprint(fd, "quit\r\n");
  196. close(fd);
  197. Bterm(&bin);
  198. return 0;
  199. }
  200. void
  201. usage(void)
  202. {
  203. fprint(2, "usage: aux/cddb [-DTt] [-s server] query diskid n ...\n");
  204. exits("usage");
  205. }
  206. void
  207. main(int argc, char **argv)
  208. {
  209. int i;
  210. Toc toc;
  211. ARGBEGIN{
  212. case 'D':
  213. debug = 1;
  214. break;
  215. case 's':
  216. server = EARGF(usage());
  217. break;
  218. case 'T':
  219. Tflag = 1;
  220. /*FALLTHROUGH*/
  221. case 't':
  222. tflag = 1;
  223. break;
  224. }ARGEND
  225. if(argc < 3 || strcmp(argv[0], "query") != 0)
  226. usage();
  227. toc.diskid = strtoul(argv[1], 0, 16);
  228. toc.ntrack = atoi(argv[2]);
  229. if(argc != 3+toc.ntrack+1)
  230. sysfatal("argument count does not match given ntrack");
  231. for(i=0; i<=toc.ntrack; i++)
  232. toc.track[i].n = atoi(argv[3+i]);
  233. if(cddbfilltoc(&toc) < 0)
  234. exits("whoops");
  235. dumpcddb(&toc);
  236. exits(nil);
  237. }