cddb.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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 int
  33. cddbfilltoc(Toc *t)
  34. {
  35. int fd;
  36. int i;
  37. char *p, *q;
  38. Biobuf bin;
  39. Msf *m;
  40. char *f[10];
  41. int nf;
  42. char *id, *categ;
  43. fd = dial("tcp!freedb.freedb.org!888", 0, 0, 0);
  44. if(fd < 0) {
  45. fprint(2, "cannot dial: %r\n");
  46. return -1;
  47. }
  48. Binit(&bin, fd, OREAD);
  49. if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) {
  50. died:
  51. close(fd);
  52. Bterm(&bin);
  53. fprint(2, "error talking to server\n");
  54. if(p) {
  55. p[Blinelen(&bin)-1] = 0;
  56. fprint(2, "server says: %s\n", p);
  57. }
  58. return -1;
  59. }
  60. fprint(fd, "cddb hello gre plan9 9cd 1.0\r\n");
  61. if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
  62. goto died;
  63. fprint(fd, "cddb query %8.8lux %d", diskid(t), t->ntrack);
  64. DPRINT(2, "cddb query %8.8lux %d", diskid(t), t->ntrack);
  65. for(i=0; i<t->ntrack; i++) {
  66. m = &t->track[i].start;
  67. fprint(fd, " %d", (m->m*60+m->s)*75+m->f);
  68. DPRINT(2, " %d", (m->m*60+m->s)*75+m->f);
  69. }
  70. m = &t->track[t->ntrack-1].end;
  71. fprint(fd, " %d\r\n", m->m*60+m->s);
  72. DPRINT(2, " %d\r\n", m->m*60+m->s);
  73. if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
  74. goto died;
  75. p[Blinelen(&bin)-1] = 0;
  76. DPRINT(2, "cddb: %s\n", p);
  77. nf = tokenize(p, f, nelem(f));
  78. if(nf < 1)
  79. goto died;
  80. switch(atoi(f[0])) {
  81. case 200: /* exact match */
  82. if(nf < 3)
  83. goto died;
  84. categ = f[1];
  85. id = f[2];
  86. break;
  87. case 211: /* close matches */
  88. if((p = Brdline(&bin, '\n')) == nil)
  89. goto died;
  90. if(p[0] == '.') /* no close matches? */
  91. goto died;
  92. p[Blinelen(&bin)-1] = '\0';
  93. /* accept first match */
  94. nf = tokenize(p, f, nelem(f));
  95. if(nf < 2)
  96. goto died;
  97. categ = f[0];
  98. id = f[1];
  99. /* snarf rest of buffer */
  100. while(p[0] != '.') {
  101. if((p = Brdline(&bin, '\n')) == nil)
  102. goto died;
  103. p[Blinelen(&bin)-1] = '\0';
  104. DPRINT(2, "cddb: %s\n", p);
  105. }
  106. break;
  107. case 202: /* no match */
  108. default:
  109. goto died;
  110. }
  111. /* fetch results for this cd */
  112. fprint(fd, "cddb read %s %s\r\n", categ, id);
  113. do {
  114. if((p = Brdline(&bin, '\n')) == nil)
  115. goto died;
  116. q = p+Blinelen(&bin)-1;
  117. while(isspace(*q))
  118. *q-- = 0;
  119. DPRINT(2, "cddb %s\n", p);
  120. if(strncmp(p, "DTITLE=", 7) == 0)
  121. t->title = estrdup(p+7);
  122. else if(strncmp(p, "TTITLE", 6) == 0 && isdigit(p[6])) {
  123. i = atoi(p+6);
  124. if(i < t->ntrack) {
  125. p += 6;
  126. while(isdigit(*p))
  127. p++;
  128. if(*p == '=')
  129. p++;
  130. t->track[i].title = estrdup(p);
  131. }
  132. }
  133. } while(*p != '.');
  134. fprint(fd, "quit\r\n");
  135. close(fd);
  136. Bterm(&bin);
  137. return 0;
  138. }
  139. void
  140. cddbproc(void *v)
  141. {
  142. Drive *d;
  143. Toc t;
  144. threadsetname("cddbproc");
  145. d = v;
  146. while(recv(d->cdbreq, &t))
  147. if(cddbfilltoc(&t) == 0)
  148. send(d->cdbreply, &t);
  149. }