cddb.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #include "acd.h"
  2. #include <ctype.h>
  3. /* see CDDBPROTO */
  4. static ulong
  5. cddb_sum(int n)
  6. {
  7. int ret;
  8. ret = 0;
  9. while(n > 0) {
  10. ret += n%10;
  11. n /= 10;
  12. }
  13. return ret;
  14. }
  15. static ulong
  16. diskid(Toc *t)
  17. {
  18. int i, n, tmp;
  19. Msf *ms, *me;
  20. n = 0;
  21. for(i=0; i < t->ntrack; i++)
  22. n += cddb_sum(t->track[i].start.m*60+t->track[i].start.s);
  23. ms = &t->track[0].start;
  24. me = &t->track[t->ntrack].start;
  25. tmp = (me->m*60+me->s) - (ms->m*60+ms->s);
  26. /*
  27. * the spec says n%0xFF rather than n&0xFF. it's unclear which is correct.
  28. * most CDs are in the database under both entries.
  29. */
  30. return ((n & 0xFF) << 24 | (tmp << 8) | t->ntrack);
  31. }
  32. static void
  33. append(char **d, char *s)
  34. {
  35. char *r;
  36. if (*d == nil)
  37. *d = estrdup(s);
  38. else {
  39. r = emalloc(strlen(*d) + strlen(s) + 1);
  40. strcpy(r, *d);
  41. strcat(r, s);
  42. free(*d);
  43. *d = r;
  44. }
  45. }
  46. static int
  47. cddbfilltoc(Toc *t)
  48. {
  49. int fd;
  50. int i;
  51. char *p, *q;
  52. Biobuf bin;
  53. Msf *m;
  54. char *f[10];
  55. int nf;
  56. char *id, *categ;
  57. char gottrack[MTRACK];
  58. int gottitle;
  59. fd = dial("tcp!freedb.freedb.org!888", 0, 0, 0);
  60. if(fd < 0) {
  61. fprint(2, "cannot dial: %r\n");
  62. return -1;
  63. }
  64. Binit(&bin, fd, OREAD);
  65. if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) {
  66. died:
  67. close(fd);
  68. Bterm(&bin);
  69. fprint(2, "error talking to server\n");
  70. if(p) {
  71. p[Blinelen(&bin)-1] = 0;
  72. fprint(2, "server says: %s\n", p);
  73. }
  74. return -1;
  75. }
  76. fprint(fd, "cddb hello gre plan9 9cd 1.0\r\n");
  77. if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
  78. goto died;
  79. fprint(fd, "cddb query %8.8lux %d", diskid(t), t->ntrack);
  80. DPRINT(2, "cddb query %8.8lux %d", diskid(t), t->ntrack);
  81. for(i=0; i<t->ntrack; i++) {
  82. m = &t->track[i].start;
  83. fprint(fd, " %d", (m->m*60+m->s)*75+m->f);
  84. DPRINT(2, " %d", (m->m*60+m->s)*75+m->f);
  85. }
  86. m = &t->track[t->ntrack-1].end;
  87. fprint(fd, " %d\r\n", m->m*60+m->s);
  88. DPRINT(2, " %d\r\n", m->m*60+m->s);
  89. if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
  90. goto died;
  91. p[Blinelen(&bin)-1] = 0;
  92. DPRINT(2, "cddb: %s\n", p);
  93. nf = tokenize(p, f, nelem(f));
  94. if(nf < 1)
  95. goto died;
  96. switch(atoi(f[0])) {
  97. case 200: /* exact match */
  98. if(nf < 3)
  99. goto died;
  100. categ = f[1];
  101. id = f[2];
  102. break;
  103. case 211: /* close matches */
  104. if((p = Brdline(&bin, '\n')) == nil)
  105. goto died;
  106. if(p[0] == '.') /* no close matches? */
  107. goto died;
  108. p[Blinelen(&bin)-1] = '\0';
  109. /* accept first match */
  110. nf = tokenize(p, f, nelem(f));
  111. if(nf < 2)
  112. goto died;
  113. categ = f[0];
  114. id = f[1];
  115. /* snarf rest of buffer */
  116. while(p[0] != '.') {
  117. if((p = Brdline(&bin, '\n')) == nil)
  118. goto died;
  119. p[Blinelen(&bin)-1] = '\0';
  120. DPRINT(2, "cddb: %s\n", p);
  121. }
  122. break;
  123. case 202: /* no match */
  124. default:
  125. goto died;
  126. }
  127. /* fetch results for this cd */
  128. fprint(fd, "cddb read %s %s\r\n", categ, id);
  129. memset(gottrack, 0, sizeof(gottrack));
  130. gottitle = 0;
  131. do {
  132. if((p = Brdline(&bin, '\n')) == nil)
  133. goto died;
  134. q = p+Blinelen(&bin)-1;
  135. while(isspace(*q))
  136. *q-- = 0;
  137. DPRINT(2, "cddb %s\n", p);
  138. if(strncmp(p, "DTITLE=", 7) == 0) {
  139. if (gottitle)
  140. append(&t->title, p + 7);
  141. else
  142. t->title = estrdup(p+7);
  143. gottitle = 1;
  144. } else if(strncmp(p, "TTITLE", 6) == 0 && isdigit(p[6])) {
  145. i = atoi(p+6);
  146. if(i < t->ntrack) {
  147. p += 6;
  148. while(isdigit(*p))
  149. p++;
  150. if(*p == '=')
  151. p++;
  152. if (gottrack[i])
  153. append(&t->track[i].title, p);
  154. else
  155. t->track[i].title = estrdup(p);
  156. gottrack[i] = 1;
  157. }
  158. }
  159. } while(*p != '.');
  160. fprint(fd, "quit\r\n");
  161. close(fd);
  162. Bterm(&bin);
  163. return 0;
  164. }
  165. void
  166. cddbproc(void *v)
  167. {
  168. Drive *d;
  169. Toc t;
  170. threadsetname("cddbproc");
  171. d = v;
  172. while(recv(d->cdbreq, &t))
  173. if(cddbfilltoc(&t) == 0)
  174. send(d->cdbreply, &t);
  175. }