/* ** playlist_dispatch.c ** $Id: playlist_dispatch.c,v 1.5 2002/05/20 00:45:56 brian Exp $ */ #include "mod_mp3.h" #include #include "playlist_dispatch.h" DB * playlist_db_connect(mp3_conf *cfg, playlist_context *context) { DB *dbh = NULL; int ret=0; context->playlist = cfg->playlist; if ((ret = db_create(&dbh, NULL, 0)) != 0) { fprintf(stderr, "mod_mp3: db_create: %s\n", db_strerror(ret)); return NULL; } dbh->set_errfile(dbh, stderr); dbh->set_errpfx(dbh, "mod_mp3"); if ((ret = dbh->set_re_source(dbh, cfg->playlist)) != 0) { dbh->err(dbh, ret, "%s: open", cfg->playlist); (void)dbh->close(dbh, 0); return NULL; } if ((ret = dbh->open(dbh, NULL, NULL, DB_RECNO, DB_CREATE, 0664)) != 0) { dbh->err(dbh, ret, "%s: open", cfg->playlist); (void)dbh->close(dbh, 0); return NULL; } return dbh; } MP3_EXPORT(int) playlist_request(void *info, void *passcfg, pool *p) { playlist_context *context = (playlist_context *)info; mp3_conf *cfg = (mp3_conf *)passcfg; int ret = 0; context->playlist = cfg->playlist; context->each_counter = 0; if (!context->dbh) { context->dbh = playlist_db_connect(cfg, context); } if (!context->dbh) { return 1; } if (context->cursor) { if ((ret = context->cursor->c_close(context->cursor)) != 0) { context->dbh->err(context->dbh, ret, "DBcursor->close"); return 1; } } return 0; } mp3_data * playlist_random(playlist_context *context, pool *p) { int x = 0; /* for better PRNG seeding with microseconds versus current seconds */ struct timeval tv_struct[2]; gettimeofday(tv_struct, 0); srandom (tv_struct[0].tv_sec % tv_struct[0].tv_usec); if (!context->total || !context->seen) { context->total = playlist_count(context, p, NULL, NULL); context->seen = ap_pcalloc(p, sizeof(int) * context->total); memset(context->seen, 0, sizeof(int) * context->total); context->each_counter = 0; } if (context->each_counter == context->total) { context->total = 0; /* We should free() ->seen right here */ return NULL; } else { context->each_counter++; } for(;;) { x = ((int)random() % context->total); /* File lines begin with 1 */ x++; if(context->seen[x]) { continue; } else { context->seen[x] = 1; } printf("Looking for %d \n", x); return playlist_get(context, p, ap_psprintf(p,"%d",x)); } } MP3_EXPORT(void *) playlist_create(pool *p) { playlist_context *context = ap_pcalloc(p, sizeof(playlist_context)); memset(context, 0, sizeof(playlist_context)); context->playlist = NULL; context->dbh = NULL; context->cursor = NULL; context->each_counter = 0; context->total = 0; return context; } MP3_EXPORT(void) playlist_cleanup(void *data) { playlist_context *context = (playlist_context *)data; int ret = 0; if (context->cursor && (ret = context->cursor->c_close(context->cursor)) != 0) { context->dbh->err(context->dbh, ret, "DBcursor->close"); } context->dbh->close(context->dbh,0); } MP3_EXPORT(void) playlist_cursor_cleanup(void *data) { playlist_context *context = (playlist_context *)data; int ret = 0; if (context->cursor && (ret = context->cursor->c_close(context->cursor)) != 0) { context->dbh->err(context->dbh, ret, "DBcursor->close"); } context->cursor = NULL; } MP3_EXPORT(mp3_data *) playlist_get(void *info, pool *p, char *signature) { playlist_context *context = (playlist_context *)info; DBT key, value; DBC *cursor = NULL; db_recno_t recno = atoi(signature); int ret = 0; mp3_data *data = NULL; const char *filename = NULL; const char *signature = NULL; memset(&key, 0, sizeof(key)); memset(&value, 0, sizeof(value)); key.data = &recno; key.size = sizeof(db_recno_t); if ((ret = context->dbh->cursor(context->dbh, NULL, &cursor, 0)) != 0) { context->dbh->err(context->dbh, ret, "DB->cursor"); return NULL; } if ((ret = cursor->c_get(cursor, &key, &value, DB_SET)) != 0) { context->dbh->err(context->dbh, ret, "Error %s", context->playlist); exit(1); return NULL; } filename = ap_pstrndup(p, (char *)value.data, value.size); signature = ap_psprintf(p, "%lu", *(u_long *)key.data); data = mp3_create_content(p, (char *)filename, (char *)filename, (char *)signature, 0); if ((ret = cursor->c_close(cursor)) != 0) { context->dbh->err(context->dbh, ret, "DBcursor->close"); } #ifdef DEBUG printf("VAL: %s \n", (char *)value.data); #endif return data; } MP3_EXPORT(mp3_data *) playlist_each(void *info, pool *p, array_header *files, const char *token, int random) { playlist_context *context = (playlist_context *)info; DBT key, value; int ret = 0; char **files_fetch = NULL; const char *filename = NULL; const char *signature = NULL; memset(&key, 0, sizeof(DBT)); memset(&value, 0, sizeof(DBT)); /* key.data =&recno; key.size = sizeof(recno); */ if (random) { return playlist_random(context, p); } if(files) { files_fetch = (char **)files->elts; if (context->each_counter == files->nelts) { context->each_counter = 0; return NULL; } context->each_counter++; return playlist_get(info, p, files_fetch[context->each_counter - 1]); #ifdef DEAD_CODE /* No token support at this time, if you write it, put it here */ } else if (token) { #endif } else { if (context->cursor == NULL) { if ((ret = context->dbh->cursor(context->dbh, NULL, &context->cursor, 0)) != 0) { context->dbh->err(context->dbh, ret, "DB->cursor"); return NULL; } ap_register_cleanup(p, context, playlist_cursor_cleanup, ap_null_cleanup); } while ((ret = context->cursor->c_get(context->cursor, &key, &value, DB_NEXT)) == 0) { /* This may eat up to much memory */ filename = ap_pstrndup(p, (char *)value.data, value.size); signature = ap_psprintf(p, "%lu", *(u_long *)key.data); return mp3_create_content(p, (char *)filename, (char *)filename, (char *)signature, 0); } } if (context->cursor && (ret = context->cursor->c_close(context->cursor)) != 0) { context->dbh->err(context->dbh, ret, "DBcursor->close"); } return NULL; } MP3_EXPORT(array_header *) playlist_search(void *info, pool *p, const char *pattern, int limit) { playlist_context *context = (playlist_context *)info; int x = 0; int ret = 0; array_header *signatures = NULL; DBT key, value; DBC *cursor = NULL; if(pattern) { while ((ret = context->cursor->c_get(cursor, &key, &value, DB_NEXT)) == 0) { if(!mp3_match(pattern, (char *)value.data)) { if(!signatures) signatures = ap_make_array(p, 25, sizeof (mp3_data *)); *(char **) ap_push_array (signatures) = ap_pstrdup (p, (char *)value.data); } if (limit && signatures->nelts == limit) { break; } } } else { /* Boundry checking, we could pass back to many signatures */ signatures = ap_make_array(p, 25, sizeof (char *)); while ((ret = context->cursor->c_get(cursor, &key, &value, DB_NEXT)) == 0) { x++; *(char **) ap_push_array (signatures) = ap_psprintf (p, "%d", x); } } return signatures; } #ifdef DEAD_CODE /* We don't support creating playlists, we just read them */ /* Someone of course is welcome to write this code */ MP3_EXPORT(int) playlist_set(void *info, pool *p, mp3_data *bank) { // playlist_context *context = (playlist_context *)info; return 0; } #endif MP3_EXPORT(int) playlist_count(void *info, pool *p, array_header *files, const char *token) { playlist_context *context = (playlist_context *)info; DBT key, value; DBC *cursor = NULL; int ret = 0; int count = 0; if (files) { return files->nelts; } memset(&key, 0, sizeof(key)); memset(&value, 0, sizeof(value)); if ((ret = context->dbh->cursor(context->dbh, NULL, &cursor, 0)) != 0) { context->dbh->err(context->dbh, ret, "DB->cursor"); return 0; } while ((ret = cursor->c_get(cursor, &key, &value, DB_NEXT)) == 0) { count++; } if (cursor && (ret = cursor->c_close(cursor)) != 0) { context->dbh->err(context->dbh, ret, "DBcursor->close"); } return count; } mp3_dispatch playlist = { "playlist", /* Name of the dispatch */ playlist_create, /* Create a context */ NULL, /* Init to run when server forks for child */ playlist_request, /* Init to run when request is made */ playlist_get, /* Get request */ NULL, /* Set an item request */ playlist_each, /* Each operator to run through entire list */ playlist_count, /* Method to count available files */ playlist_search, /* This returns filenames based on a pattern, if no pattern is give then it should return all signatures in the system.*/ };