00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00034 #include "html.h"
00035 #include "inf.h"
00036
00043 char chaine[MAX_STRING];
00044
00055 static char *ascii2rq(char *orig)
00056 {
00057 char *hexatable = "0123456789ABCDEF";
00058 char a;
00059 int i=0, j=0;
00060
00061 while ((a=orig[i++]) != '\0') {
00062 if (strchr("%;?:@&=+$<>#\"{}|\\^[]`", a)) {
00063 chaine[j++] = '%';
00064 chaine[j++] = hexatable[a>>4];
00065 chaine[j++] = hexatable[a&0xf];
00066 } else if (a == ' ') {
00067 chaine[j++] = '+';
00068 } else {
00069 chaine[j++] = a;
00070 }
00071 }
00072 chaine[j] = '\0';
00073 return chaine;
00074 }
00075
00087 static void list_songs(request_rec * r, struct mu_ent *p, mu_config * conf)
00088 {
00089 struct mu_ent *q = p;
00090 unsigned short i = 0, j = 1;
00091 char *current = "*", *new = NULL;
00092
00093 while (q) {
00094
00095 if ((conf->options & (MI_SEARCH | MI_RECURSIVE)) == (MI_SEARCH | MI_RECURSIVE)) {
00096 new = ap_make_dirstr_parent(r->pool, q->file);
00097
00098 if (strcmp(current, new)) {
00099 current = new;
00100 if ((current[0] == '\0') || (current[1] == '\0'))
00101 ap_rputs(" <tr class=\"title\"><th align=\"left\" colspan=\"10\">in Current Directory</th>\n", r);
00102 else
00103 ap_rvputs(r, " <tr class=\"title\"><th align=\"left\" colspan=\"10\">in <a href=\"", current, "\">", current, "</a></th>\n", NULL);
00104 j = 0;
00105 }
00106 }
00107
00108 if (j) {
00109 ap_rputs(" <tr class=\"odd\">\n", r);
00110 j = 0;
00111 } else {
00112 ap_rputs(" <tr class=\"even\">\n", r);
00113 j = 1;
00114 }
00115
00116 if (conf->options & (MI_ALLOWDWNLD | MI_ALLOWSTREAM)) {
00117
00118 ap_rputs(" <td class=\"Select\">\n", r);
00119
00120 if (conf->options & MI_ALLOWSTREAM)
00121 ap_rvputs(r, " <input type=\"checkbox\" name=\"file\" value=\"",
00122 q->file, "\">\n", NULL);
00123
00124
00125 if (conf->options & MI_ALLOWDWNLD)
00126 ap_rvputs(r, " <a href=\"", ap_escape_uri(r->pool, q->file), "\">"
00127 "<img alt=\"[F]\" src=\"", conf->fetch_icon, "\"></a>\n", NULL);
00128
00129 if (conf->options & MI_ALLOWSTREAM)
00130 ap_rvputs(r, " <a href=\"?file=", ascii2rq(q->file), "&action=playlist\">"
00131 "<img alt=\"[S]\" src=\"", conf->sound_icon, "\"></a>\n", NULL);
00132
00133 ap_rputs(" </td>\n", r);
00134 }
00135
00136 for (i = 0; conf->fields[i] != '\0'; i++) {
00137 switch (conf->fields[i]) {
00138 case SB_TITLE:
00139 ap_rvputs(r, " <td class=\"Title\">", q->title, "</td>\n", NULL);
00140 break;
00141 case SB_TRACK:
00142 if (q->track)
00143 ap_rprintf(r, " <td class=\"Track\">%d</td>\n", q->track);
00144 else
00145 ap_rputs( " <td></td>\n", r);
00146 break;
00147 case SB_POSN:
00148 if (q->posn)
00149 ap_rprintf(r, " <td class=\"Disc\">%d</td>\n", q->posn);
00150 else
00151 ap_rputs( " <td></td>\n", r);
00152 break;
00153 case SB_ARTIST:
00154 if (q->artist)
00155 ap_rvputs(r, " <td class=\"Artist\">", q->artist, "</td>\n", NULL);
00156 else
00157 ap_rputs( " <td></td>\n", r);
00158 break;
00159 case SB_LENGTH:
00160 if (conf->options & MI_QUICKPL)
00161 break;
00162 if (q->length)
00163 ap_rprintf(r, " <td class=\"Duration\">%ld:%.2ld</td>\n", q->length / 60, q->length % 60);
00164 else
00165 ap_rputs( " <td></td>\n", r);
00166 break;
00167 case SB_BITRATE:
00168 if (conf->options & MI_QUICKPL)
00169 break;
00170 if (q->bitrate)
00171 ap_rprintf(r, " <td class=\"Bitrate\">%ld</td>\n", q->bitrate >> 10);
00172 else
00173 ap_rputs( " <td></td>\n", r);
00174 break;
00175 case SB_DATE:
00176 if (q->date)
00177 ap_rprintf(r, " <td class=\"Date\">%d </td>\n", q->date);
00178 else
00179 ap_rputs( " <td></td>\n", r);
00180 break;
00181 case SB_ALBUM:
00182 if (q->album)
00183 ap_rvputs(r, " <td class=\"Album\">", q->album, "</td>\n", NULL);
00184 else
00185 ap_rputs( " <td></td>\n", r);
00186 break;
00187 case SB_FILETYPE:
00188 switch(q->filetype) {
00189 case FT_MP3:
00190 ap_rvputs(r, " <td>MP3</td>\n", NULL);
00191 break;
00192 case FT_OGG:
00193 ap_rvputs(r, " <td>OGG</td>\n", NULL);
00194 break;
00195 }
00196 break;
00197 case SB_GENRE:
00198 if (q->genre)
00199 ap_rvputs(r, " <td class=\"Genre\">", q->genre, "</td>\n", NULL);
00200 else
00201 ap_rputs( " <td></td>\n", r);
00202 break;
00203 }
00204 }
00205 ap_rputs(" </tr>\n", r);
00206 q = q->next;
00207 }
00208
00209 }
00210
00222 char treat_args(request_rec * r, mu_config * conf)
00223 {
00224 const char *s = r->args;
00225 const char *p;
00226 unsigned short i;
00227
00228 if ((s == NULL) || (*s == '\0'))
00229 return 'A';
00230
00231 while (s[0]){
00232 p = ap_getword(r->pool, &s, '&');
00233 if (!strncmp(p, "action=", 7)) {
00234 p += 7;
00235 if ((!strcmp(p, "playlist") || !strcmp(p, "Play+Selected")) && (conf->options & MI_ALLOWSTREAM)) {
00236 return 'L';
00237 } else if ((!strcmp(p, "playall") || !strcmp(p, "Play+All")) && (conf->options & MI_ALLOWSTREAM)) {
00238 return 'P';
00239 } else if (!strcmp(p, "Shuffle+All") && (conf->options & MI_ALLOWSTREAM)) {
00240 conf->order[0] = SB_RANDOM;
00241 conf->order[1] = SB_DEFAULT;
00242 set_fctptrs(conf);
00243 return 'P';
00244 } else if (!strcmp(p, "Search") && (conf->options & MI_ALLOWSEARCH) && (conf->search[0] != '\0')) {
00245 conf->options |= MI_SEARCH;
00246 if (!conf->cache_path)
00247 conf->options |= MI_QUICKPL;
00248 } else if (!strcmp(p, "Recursive+Search") && (conf->options & MI_ALLOWSEARCH) && (conf->search[0] != '\0')) {
00249 conf->play_recursive |= MI_SEARCH|MI_RECURSIVE;
00250 conf->order[0] = SB_URI;
00251 set_fctptrs(conf);
00252 }
00253
00254 }
00255 else if (!strncmp(p, "sort=", 5)) {
00256 p += 5;
00257 for (i = ARG_NUMBER-strlen(p)-1; i!=0; i--)
00258 conf->order[i] = conf->order[i-strlen(p)];
00259 for (i=0; (i<strlen(p)) && (i<ARG_NUMBER); i++)
00260 conf->order[i] = p[i];
00261 conf->order[ARG_NUMBER-1] = SB_DEFAULT;
00262 set_fctptrs(conf);
00263 }
00264 else if (!strncmp(p, "option=", 7)) {
00265 p += 7;
00266 if (!strcmp(p, "recursive")) {
00267 conf->play_recursive |= MI_RECURSIVE;
00268 }
00269 else if (!strcmp(p, "shuffle")) {
00270 conf->order[0] = SB_RANDOM;
00271 conf->order[1] = SB_DEFAULT;
00272 set_fctptrs(conf);
00273 }
00274 else if (!strcmp(p, "quick")) {
00275 conf->options |= MI_QUICKPL;
00276 }
00277 else {
00278 conf->search = ap_pstrdup(r->pool, p);
00279 for (i=0; p[i]; i++) {
00280 if (p[i] == '+') {
00281 conf->search[i] = ' ';
00282 }
00283 }
00284 ap_unescape_url(conf->search);
00285 }
00286 }
00287 }
00288
00289 return 'A';
00290 }
00291
00302 void send_url(request_rec *r, char *uri, char *command)
00303 {
00304 char *prefix = malloc(MAX_PREFIX);
00305 char str_port[6];
00306 char *bufcoded, *decoded;
00307 unsigned short l;
00308
00309 strcpy(prefix, "http://");
00310
00311 if (r->connection->user) {
00312
00313 const char *auth = ap_table_get(r->headers_in, "Authorization");
00314 if (auth) {
00315 bufcoded = strrchr(auth, ' ');
00316 bufcoded++;
00317 decoded = (char *)ap_palloc(r->pool, 1 + ap_base64decode_len(bufcoded));
00318 l = ap_base64decode(decoded, bufcoded);
00319 decoded[l] = '\0';
00320 strcat(prefix, decoded);
00321 }
00322 strcat(prefix, "@");
00323 }
00324
00325
00326 strcat(prefix, r->hostname);
00327
00328
00329 if (r->server->port != 80) {
00330 sprintf(str_port, "%u", r->server->port);
00331 strcat(prefix, ":");
00332 strcat(prefix, str_port);
00333 }
00334
00335
00336 ap_rvputs(r, prefix, ap_escape_uri(r->pool, uri), NULL);
00337 if (command)
00338 ap_rvputs(r, command, NULL);
00339 ap_rvputs(r, "\n", NULL);
00340
00341 free(prefix);
00342 }
00343
00353 void send_head(request_rec * r, mu_config * conf)
00354 {
00355 char *s, *t, *u;
00356 FILE *in = NULL;
00357
00358 s = ap_pstrdup(r->pool, r->uri);
00359
00360 ap_rvputs(r, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n"
00361 "<HTML>\n"
00362 "<HEAD>\n"
00363 " <META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"
00364 " <link rel=\"stylesheet\" type=\"text/css\" href=\"", conf->css, "\">\n", NULL);
00365
00366 ap_rvputs(r, " <TITLE>Musical index of ", r->uri, "</TITLE>\n"
00367 "</HEAD>\n"
00368 "<BODY>\n", NULL);
00369
00370 u = s + strlen(s);
00371 if (strlen(s) > 1)
00372 u--;
00373 if (*u == '/')
00374 *u = '\0';
00375
00376 ap_rputs("<table id=\"header\">\n"
00377 " <tr>\n"
00378 " <td id=\"mainicon\">\n"
00379 " <img alt=\"Dir\" src=\"", r);
00380
00381 if ((in = fopen(ap_pstrcat(r->pool, r->filename, "/", "cover.png", NULL), "r"))) {
00382 ap_rputs("cover.png", r);
00383 fclose(in);
00384 }
00385 else if ((in = fopen(ap_pstrcat(r->pool, r->filename, "/", "cover.jpg", NULL), "r"))) {
00386 ap_rputs("cover.jpg", r);
00387 fclose(in);
00388 }
00389 else {
00390 ap_rputs(conf->cd_icon, r);
00391 }
00392
00393 ap_rputs("\">\n"
00394 " </td>\n", r);
00395
00396 t = u = s + 1;
00397
00398 ap_rvputs(r, " <td id=\"maintitle\">\n"
00399 " <h1>\n"
00400 " <a href=\"/\">", conf->title, "</a>\n", NULL);
00401
00402 do {
00403 while ((*u != '/') && (*u != '\0'))
00404 u++;
00405
00406 if (u != s + 1)
00407 ap_rvputs(r, " <img src=\"", conf->arrow,
00408 "\" alt=\"=>\">\n", NULL);
00409
00410 *u = '\0';
00411 ap_rvputs(r, " <a href=\"", ap_escape_uri(r->pool, s), "/\">", t, "</a>\n", NULL);
00412 *u = '/';
00413 u++;
00414 t = u;
00415
00416 } while (*u != '\0');
00417
00418 ap_rputs(" </h1>\n", r);
00419
00420 if (conf->options & MI_ALLOWSTREAM)
00421 ap_rputs(" <a href=\"?option=recursive&option=shuffle&action=playall\">"
00422 "[Shuffle All]</a>\n"
00423 " <a href=\"?option=recursive&action=playall\">"
00424 "[Stream All]</a>\n", r);
00425
00426 ap_rputs(" </td>\n", r);
00427
00428
00429 if (conf->options & MI_ALLOWSEARCH){
00430 ap_rvputs(r,
00431 " <td id=\"search\">\n"
00432 " <form method=\"get\" action=\"", ap_escape_uri(r->pool, r->uri), "\""
00433 "enctype=\"application/x-www-form-urlencoded\" name=\"searching\">\n"
00434 " <p>\n"
00435 " <input type=\"text\" name=\"option\">\n"
00436 " <br>\n"
00437 " <input type=\"hidden\" name=\"action\" value=\"Search\">\n"
00438 " <input type=\"submit\" name=\"action\" value=\"Search\">\n"
00439 " <input type=\"submit\" name=\"action\" value=\"Recursive Search\">\n"
00440 " </p>\n"
00441 " </form>\n"
00442 " </td>\n",
00443 NULL);
00444 }
00445
00446 ap_rputs(" </tr>\n"
00447 "</table>\n"
00448 "<hr>\n<!-- begin main -->\n\n", r);
00449
00450 }
00451
00463 void send_directories(request_rec * r, struct mu_ent * p, mu_config * conf)
00464 {
00465 struct mu_ent *q = p;
00466 unsigned short i = 0, nb = 0;
00467 char *c;
00468 char temp[MAX_STRING];
00469
00470 if (!q)
00471 return;
00472
00473 if (q->filetype != FT_DIR)
00474 return;
00475
00476
00477 while (q && (q->filetype == FT_DIR)) {
00478 nb++;
00479 q = q->next;
00480 }
00481
00482 q = p;
00483
00484 ap_rprintf(r, "<!-- begin subdirs -->\n<h2>Music Directories (%d)</h2>\n\n", nb);
00485
00486 ap_rputs("<table id=\"directories\">\n", r);
00487
00488 i = 1;
00489 while (q && (q->filetype == FT_DIR)) {
00490
00491 c = ap_cpystrn(temp, q->file, MAX_STRING)-1;
00492 *c = '\0';
00493
00494 if (i == 1)
00495 ap_rputs(" <tr>\n", r);
00496
00497 ap_rvputs(r, " <td>\n"
00498 " <table>\n"
00499 " <tr>\n"
00500 " <td>\n"
00501 " <a href=\"", ap_escape_uri(r->pool, q->file), NULL);
00502
00503 if (conf->options & MI_ALLOWSTREAM)
00504 ap_rputs("?option=recursive&action=playall", r);
00505
00506 ap_rvputs(r, "\"><img "
00507 "alt=\"\" "
00508 "src=\"", conf->small_cd_icon, "\" /></a>\n"
00509 " </td>\n", NULL);
00510
00511 ap_rvputs(r, " <td>\n"
00512 " <a class=\"subdir\" href=\"", ap_escape_uri(r->pool, q->file), "\">",
00513 temp, "</a><br>\n", NULL);
00514
00515 if (conf->options & MI_ALLOWSTREAM) {
00516 ap_rvputs(r, " <a class=\"subdirbuttons\" href=\"",
00517 ap_escape_uri(r->pool, q->file), "?option=recursive&option=shuffle&option=playall\">"
00518 "[Shuffle]</a>\n", NULL);
00519
00520 ap_rvputs(r, " <a class=\"subdirbuttons\" href=\"",
00521 ap_escape_uri(r->pool, q->file), "?option=recursive&action=playall\">"
00522 "[Stream]</a>\n", NULL);
00523 }
00524
00525 ap_rputs(" </td>\n"
00526 " </tr>\n"
00527 " </table>\n"
00528 " </td>\n",r);
00529
00530 if (i == 3) {
00531 i = 0;
00532 ap_rputs(" </tr>\n", r);
00533 }
00534 i++;
00535 q = q->next;
00536 }
00537
00538 ap_rputs("</table>\n<hr>\n<!-- end subdirs -->\n\n", r);
00539 }
00540
00554 void send_tracks(request_rec * r, struct mu_ent *p, mu_config * conf)
00555 {
00556 struct mu_ent *q = p;
00557 unsigned short i = 0, nb = 0;
00558 char *myargs = NULL;
00559
00560
00561 for (q=p; (q!=NULL); q = q->next) {
00562 if (q->filetype != FT_DIR)
00563 nb++;
00564 }
00565
00566
00567 q = p;
00568 while (q) {
00569 if (q->filetype != FT_DIR)
00570 break;
00571 q = q->next;
00572 }
00573
00574 if (q == NULL)
00575 return;
00576
00577 ap_rputs("<!-- begin tracks -->\n<h2>", r);
00578
00579 if (conf->options & MI_SEARCH)
00580 ap_rputs("Result", r);
00581 else
00582 ap_rputs("Song", r);
00583
00584 ap_rprintf(r, " List (%d)</h2>\n\n", nb);
00585
00586 ap_rvputs(r, "<form method=\"get\" action=\"", ap_escape_uri(r->pool, r->uri), "\" "
00587 "enctype=\"application/x-www-form-urlencoded\" name=\"form\">\n", NULL);
00588
00589 ap_rputs("<table width=\"100%\" cellspacing=\"0\" border=\"0\">\n", r);
00590
00591 ap_rputs(" <tr class=\"title\">\n", r);
00592
00593 if (conf->options & (MI_ALLOWDWNLD | MI_ALLOWSTREAM))
00594 ap_rputs(" <th id=\"Select\">Select</th>\n", r);
00595
00596
00597
00598
00599
00600 if (conf->options & MI_SEARCH) {
00601 if (!(strncmp(strrchr(r->args, '&'), "&sort=", 6)))
00602 myargs = ap_pstrndup(r->pool, r->args, strlen(r->args)-7);
00603 else
00604 myargs = ap_pstrdup(r->pool, r->args);
00605 }
00606
00607 for (i = 0; conf->fields[i] != '\0'; i++) {
00608 switch (conf->fields[i]) {
00609 case SB_TITLE:
00610 if (conf->options & MI_SEARCH)
00611 ap_rprintf(r, " <th id=\"Title\"><a href=\"?%s&sort=%c\">Title<a></th>\n", myargs, SB_TITLE);
00612 else
00613 ap_rprintf(r, " <th id=\"Title\"><a href=\"?sort=%c\">Title</a></th>\n", SB_TITLE);
00614 break;
00615 case SB_TRACK:
00616 if (conf->options & MI_SEARCH)
00617 ap_rprintf(r, " <th id=\"Track\"><a href=\"?%s&sort=%c\">Track</a></th>\n", myargs, SB_TRACK);
00618 else
00619 ap_rprintf(r, " <th id=\"Track\"><a href=\"?sort=%c\">Track</a></th>\n", SB_TRACK);
00620 break;
00621 case SB_POSN:
00622 if (conf->options & MI_SEARCH)
00623 ap_rprintf(r, " <th id=\"Disc\"><a href=\"?%s&sort=%c\">Disc</a></th>\n", myargs, SB_POSN);
00624 else
00625 ap_rprintf(r, " <th id=\"Disc\"><a href=\"?sort=%c\">Disc</a></th>\n", SB_POSN);
00626 break;
00627 case SB_ARTIST:
00628 if (conf->options & MI_SEARCH)
00629 ap_rprintf(r, " <th id=\"Artist\"><a href=\"?%s&sort=%c\">Artist</a></th>\n", myargs, SB_ARTIST);
00630 else
00631 ap_rprintf(r, " <th id=\"Artist\"><a href=\"?sort=%c\">Artist</a></th>\n", SB_ARTIST);
00632 break;
00633 case SB_LENGTH:
00634 if (!(conf->options & MI_QUICKPL)) {
00635 if (conf->options & MI_SEARCH)
00636 ap_rprintf(r, " <th id=\"Duration\"><a href=\"?%s&sort=%c\">Duration</a></th>\n", myargs, SB_LENGTH);
00637 else
00638 ap_rprintf(r, " <th id=\"Duration\"><a href=\"?sort=%c\">Duration</a></th>\n", SB_LENGTH);
00639 }
00640 break;
00641 case SB_BITRATE:
00642 if (!(conf->options & MI_QUICKPL)) {
00643 if (conf->options & MI_SEARCH)
00644 ap_rprintf(r, " <th id=\"Bitrate\"><a href=\"?%s&sort=%c\">Bitrate</a></th>\n", myargs, SB_BITRATE);
00645 else
00646 ap_rprintf(r, " <th id=\"Bitrate\"><a href=\"?sort=%c\">Bitrate</a></th>\n", SB_BITRATE);
00647 }
00648 break;
00649 case SB_ALBUM:
00650 if (conf->options & MI_SEARCH)
00651 ap_rprintf(r, " <th id=\"Album\"><a href=\"?%s&sort=%c\">Album</a></th>\n", myargs, SB_ALBUM);
00652 else
00653 ap_rprintf(r, " <th id=\"Album\"><a href=\"?sort=%c\">Album</a></th>\n", SB_ALBUM);
00654 break;
00655 case SB_DATE:
00656 if (conf->options & MI_SEARCH)
00657 ap_rprintf(r, " <th id=\"Date\"><a href=\"?%s&sort=%c\">Date</a></th>\n", myargs, SB_DATE);
00658 else
00659 ap_rprintf(r, " <th id=\"Date\"><a href=\"?sort=%c\">Date</a></th>\n", SB_DATE);
00660 break;
00661 case SB_FILETYPE:
00662 if (conf->options & MI_SEARCH)
00663 ap_rprintf(r, " <th id=\"Filetype\"><a href=\"?%s&sort=%c\">Type</a></th>\n", myargs, SB_FILETYPE);
00664 else
00665 ap_rprintf(r, " <th id=\"Filetype\"><a href=\"?sort=%c\">Type</a></th>\n", SB_FILETYPE);
00666 break;
00667 case SB_GENRE:
00668 if (conf->options & MI_SEARCH)
00669 ap_rprintf(r, " <th id=\"Genre\"><a href=\"?%s&sort=%c\">Genre</a></th>\n", myargs, SB_GENRE);
00670 else
00671 ap_rprintf(r, " <th id=\"Genre\"><a href=\"?sort=%c\">Genre</a></th>\n", SB_GENRE);
00672 break;
00673 }
00674 }
00675 ap_rputs(" </tr>\n", r);
00676
00677 list_songs(r, q, conf);
00678
00679 if (conf->options & MI_SEARCH)
00680 ap_rputs("<tr class=\"title\"><th align=\"left\" colspan=\"10\">"
00681 "<input type=\"checkbox\" name=\"all\" onClick=\"for(var i=0;i<this.form.elements.length;i++){var inpt=this.form.elements[i];"
00682 "var m=inpt.name.match(/-/g);if((inpt.name.substr(0,4)=='file') && (m<1)) inpt.checked=this.form.all.checked}\">\n"
00683 "Select All</th>", r);
00684
00685 ap_rputs("</table>\n", r);
00686
00687 ap_rvputs(r, "<p>\n"
00688
00689
00690 " <input type=\"hidden\" name=\"sort\" value=\"", conf->order,"\">\n"
00691 " <input type=\"submit\" name=\"action\" value=\"Play Selected\">\n", NULL);
00692
00693 if (!(conf->options & MI_SEARCH))
00694 ap_rputs(" <input type=\"submit\" name=\"action\" value=\"Shuffle All\">\n"
00695 " <input type=\"submit\" name=\"action\" value=\"Play All\">\n", r);
00696
00697 ap_rputs("</p>\n</form>\n<hr>\n<!-- end tracks -->\n\n", r);
00698 }
00699
00712 void send_playlist(request_rec * r, mu_ent *p, mu_config * conf)
00713 {
00714 mu_ent *q = p;
00715 if (!p)
00716 return;
00717
00718 ap_rputs("#EXTM3U\n", r);
00719
00720 while (q)
00721 {
00722 ap_rprintf(r, "#EXTINF:%li,", q->length);
00723 if (q->artist)
00724 ap_rvputs(r, q->artist, " - ", NULL);
00725 ap_rvputs(r, q->title, NULL);
00726 if (q->album)
00727 ap_rvputs(r, " (", q->album, ")", NULL);
00728 ap_rvputs(r, "\n", NULL);
00729 send_url(r, q->uri, NULL);
00730 q = q->next;
00731 }
00732 }
00733
00744 void send_foot(request_rec * r, mu_config * conf)
00745 {
00746 ap_rprintf(r, "<!-- end main -->\n<!-- mod_musicindex v.%s -->\n", MUSIC_VERSION_STRING);
00747 ap_rprintf(r, "<!-- Authors: %s -->\n", MUSIC_AUTHORS_STRING);
00748 ap_rputs("<table border=\"0\" width=\"100%\">\n"
00749 " <tr>\n"
00750 " <td align=\"left\">\n"
00751 " <p>\n"
00752 #if 1
00753 " <a href=\"http://validator.w3.org/check/referer\">\n"
00754 #else
00755 " <a href=\"http://localhost/w3c-markup-validator/check/referer\">\n"
00756 #endif
00757 " <img src=\"http://www.w3.org/Icons/valid-html401\"\n"
00758 " alt=\"Valid HTML 4.01!\" height=\"31\" width=\"88\">\n"
00759 " </a>\n"
00760 " </p>\n"
00761 " </td>\n", r);
00762 ap_rprintf(r, " <td align=\"right\">"
00763 "<a href=\"http://freshmeat.net/projects/musicindex/\">"
00764 "MusicIndex v.%s</a></td>\n", MUSIC_VERSION_STRING);
00765 ap_rputs(" </tr>\n"
00766 "</table>\n\n</BODY>\n</HTML>", r);
00767 }