diff --git a/src/www_files.c b/src/www_files.c index 53789cd..44f4b2c 100644 --- a/src/www_files.c +++ b/src/www_files.c @@ -11,59 +11,64 @@ extern struct bbs_config conf; extern struct user_record *gUser; extern char *aha(char *input); -static char *www_decode(char *clean_url) { - char *url = (char *)malloz(strlen(clean_url) + 1); - int i; - int j = 0; - unsigned char c; - if (clean_url == NULL) { - free(url); - return NULL; - } +static int digit2nibble(int digit) { + static const char *const hex = "0123456789abcdef"; + static const char *const Hex = "0123456789ABCDEF"; - for (i = 0; i < strlen(clean_url); i++) { - if (clean_url[i] == '%') { - c = clean_url[i + 1] * 16 + clean_url[i + 2]; - url[j++] = (char)c; - url[j] = '\0'; - i += 2; - } else { - url[j++] = clean_url[i]; - url[j] = '\0'; - } - } - - return url; + char *p; + p = strchr(hex, digit); + if (p != NULL) + return p - hex; + p = strchr(Hex, digit); + if (p != NULL) + return p - Hex; + return -1; } -static char *www_encode(char *url) { - char *clean_url = (char *)malloz(strlen(url) * 3 + 1); - int i; - int j; +static char *www_decode(char *clean_url) { + stralloc url = EMPTY_STRALLOC; - if (url == NULL) { - free(clean_url); - return NULL; - } - - j = 0; - memset(clean_url, 0, strlen(url) * 3); - - for (i = 0; i < strlen(url); i++) { - if (isalnum(url[i]) || url[i] == '~' || url[i] == '.' || url[i] == '_') { - sprintf(&clean_url[j], "%c", url[i]); - j++; - } else { - sprintf(&clean_url[j], "%%%02X", url[i]); - j += 3; + assert(clean_url != NULL); + for (char *s = clean_url; *s != '\0'; ++s) { + if (*s == '+') + stralloc_append1(&url, ' '); + else if (*s != '%') + stralloc_append1(&url, *s); + else { + int hn = 0, ln = 0, ch = 0; + if (s[1] == '\0' || (hn = digit2nibble(s[1])) < 0) { + free(url.s); + return NULL; + } + if (s[2] == '\0' || (ln = digit2nibble(s[2])) < 0) { + free(url.s); + return NULL; + } + stralloc_append1(&url, hn * 16 + ln); } } + stralloc_0(&url); - return clean_url; + return url.s; +} + +static void www_encode(stralloc *clean, char *url) { + assert(clean != NULL); + assert(url != NULL); + for (char *s = url; *s != '\0'; ++s) { + if (isalnum(*s) || *s == '~' || *s == '.' || *s == '_') + stralloc_append1(clean, *s); + else if (*s == ' ') + stralloc_append1(clean, '+'); + else { + stralloc_append1(clean, '%'); + stralloc_cat_Byte(clean, *s); + } + } } void www_expire_old_links() { - char buffer[PATH_MAX]; + char pathbuf[PATH_MAX]; sqlite3 *db; sqlite3_stmt *res; int rc; @@ -71,9 +76,9 @@ void www_expire_old_links() { char *ret; time_t now = time(NULL); - snprintf(buffer, PATH_MAX, "%s/www_file_hashes.sq3", conf.bbs_path); + snprintf(pathbuf, PATH_MAX, "%s/www_file_hashes.sq3", conf.bbs_path); - rc = sqlite3_open(buffer, &db); + rc = sqlite3_open(pathbuf, &db); if (rc != SQLITE_OK) { dolog("Cannot open database: %s", sqlite3_errmsg(db)); return; @@ -91,14 +96,14 @@ void www_expire_old_links() { } int www_check_hash_expired(char *hash) { - char buffer[PATH_MAX]; + char pathbuf[PATH_MAX]; sqlite3 *db; sqlite3_stmt *res; int rc; time_t now = time(NULL); char sql[] = "select id from wwwhash where hash = ? and expiry > ?"; - snprintf(buffer, PATH_MAX, "%s/www_file_hashes.sq3", conf.bbs_path); - rc = sqlite3_open(buffer, &db); + snprintf(pathbuf, PATH_MAX, "%s/www_file_hashes.sq3", conf.bbs_path); + rc = sqlite3_open(pathbuf, &db); if (rc != SQLITE_OK) { return 1; } @@ -123,7 +128,7 @@ int www_check_hash_expired(char *hash) { } void www_add_hash_to_db(char *hash, time_t expiry) { - char buffer[PATH_MAX]; + char pathbuf[PATH_MAX]; sqlite3 *db; sqlite3_stmt *res; int rc; @@ -135,9 +140,9 @@ void www_add_hash_to_db(char *hash, time_t expiry) { char *ret; char *err_msg = 0; - snprintf(buffer, PATH_MAX, "%s/www_file_hashes.sq3", conf.bbs_path); + snprintf(pathbuf, PATH_MAX, "%s/www_file_hashes.sq3", conf.bbs_path); - rc = sqlite3_open(buffer, &db); + rc = sqlite3_open(pathbuf, &db); if (rc != SQLITE_OK) { return; } @@ -195,7 +200,7 @@ char *www_decode_hash(char *hash) { unsigned long long numbers[4]; int dir, sub, fid, uid; hashids_t *hashids = hashids_init(conf.bbs_name); - char buffer[PATH_MAX]; + char pathbuf[PATH_MAX]; sqlite3 *db; sqlite3_stmt *res; int rc; @@ -222,8 +227,8 @@ char *www_decode_hash(char *hash) { } // get filename from database - snprintf(buffer, PATH_MAX, "%s/%s.sq3", conf.bbs_path, conf.file_directories[dir]->file_subs[sub]->database); - rc = sqlite3_open(buffer, &db); + snprintf(pathbuf, PATH_MAX, "%s/%s.sq3", conf.bbs_path, conf.file_directories[dir]->file_subs[sub]->database); + rc = sqlite3_open(pathbuf, &db); if (rc != SQLITE_OK) { return NULL; } @@ -280,10 +285,8 @@ char *www_create_link(int dir, int sub, int fid) { return ret; } char *www_files_display_listing(int dir, int sub) { - char *page; - int max_len; - int len; - char buffer[4096]; + stralloc page = EMPTY_STRALLOC; + char pathbuf[PATH_MAX]; char *sql = "select id, filename, description, size, dlcount, uploaddate from files where approved=1 ORDER BY filename"; char *filename; char c; @@ -296,178 +299,118 @@ char *www_files_display_listing(int dir, int sub) { int i; char *clean_url; - page = (char *)malloz(4096); - max_len = 4096; - len = 0; + stralloc_copys(&page, "

Files: "); + stralloc_cats(&page, conf.file_directories[dir]->name); + stralloc_cats(&page, " - "); + stralloc_cats(&page, conf.file_directories[dir]->file_subs[sub]->name); + stralloc_cats(&page, "

\n"); - snprintf(buffer, 4096, "

Files: %s - %s

\n", conf.file_directories[dir]->name, conf.file_directories[dir]->file_subs[sub]->name); - if (len + strlen(buffer) > max_len - 1) { - max_len += 4096; - page = (char *)realloc(page, max_len); - } - strcat(page, buffer); - len += strlen(buffer); - - snprintf(buffer, 4096, "%s/%s.sq3", conf.bbs_path, conf.file_directories[dir]->file_subs[sub]->database); - - rc = sqlite3_open(buffer, &db); + snprintf(pathbuf, sizeof pathbuf, "%s/%s.sq3", + conf.bbs_path, conf.file_directories[dir]->file_subs[sub]->database); + rc = sqlite3_open(pathbuf, &db); if (rc != SQLITE_OK) { - free(page); + free(page.s); return NULL; } sqlite3_busy_timeout(db, 5000); rc = sqlite3_prepare_v2(db, sql, -1, &res, 0); if (rc != SQLITE_OK) { sqlite3_close(db); - free(page); + free(page.s); return NULL; } - snprintf(buffer, 4096, "\n"); - if (len + strlen(buffer) > max_len - 1) { - max_len += 4096; - page = (char *)realloc(page, max_len); - } - strcat(page, buffer); - len += strlen(buffer); - + stralloc_cats(&page, "
FilenameSizeDescription
\n"); while (sqlite3_step(res) == SQLITE_ROW) { - filename = strdup(sqlite3_column_text(res, 1)); - clean_url = www_encode(basename(filename)); - snprintf(buffer, 4096, "", conf.www_url, dir, sub, basename(clean_url), basename(filename)); - free(clean_url); - free(filename); - if (len + strlen(buffer) > max_len - 1) { - max_len += 4096; - page = (char *)realloc(page, max_len); - } - strcat(page, buffer); - len += strlen(buffer); + filename = strdup((char *)sqlite3_column_text(res, 1)); + char *base_filename = basename(filename); + stralloc_cats(&page, ""); size = sqlite3_column_int(res, 3); - - if (size > 1024 * 1024 * 1024) { - size = size / 1024 / 1024 / 1024; - c = 'G'; - } else if (size > 1024 * 1024) { - size = size / 1024 / 1024; - c = 'M'; - } else if (size > 1024) { - size = size / 1024; + stralloc_cats(&page, "", size, c); - if (len + strlen(buffer) > max_len - 1) { - max_len += 4096; - page = (char *)realloc(page, max_len); + if (size > 1024) { + size /= 1024; + c = 'M'; } - strcat(page, buffer); - len += strlen(buffer); + if (size > 1024) { + size /= 1024; + c = 'G'; + } + stralloc_cat_long(&page, size); + stralloc_append1(&page, c); + stralloc_cats(&page, ""); + stralloc_cats(&page, "\n"); - if (len + strlen(buffer) > max_len - 1) { - max_len += 4096; - page = (char *)realloc(page, max_len); - } - strcat(page, buffer); - len += strlen(buffer); + stralloc_cats(&page, "\n"); } - - snprintf(buffer, 4096, "
FilenameSizeDescription
%s
"); + stralloc_cats(&page, base_filename); + stralloc_cats(&page, ""); + int c = 'b'; + if (size > 1024) { + size /= 1024; c = 'K'; - } else { - c = 'b'; } - - snprintf(buffer, 4096, "%d%c"); description = strdup((char *)sqlite3_column_text(res, 2)); - - for (i = 0; i < strlen(description); i++) { - if (description[i] == '\n') { - description[i] = '\r'; - } + for (char *p = description; *p != '\0'; ++p) { + if (*p == '\n') + *p = '\r'; } - - snprintf(buffer, 4096, ""); - if (len + strlen(buffer) > max_len - 1) { - max_len += 4096; - page = (char *)realloc(page, max_len); - } - strcat(page, buffer); - len += strlen(buffer); - aha_out = aha(description); - - while (len + strlen(aha_out) > max_len - 1) { - max_len += 4096; - page = (char *)realloc(page, max_len); - } - strcat(page, aha_out); - len += strlen(aha_out); - + stralloc_cats(&page, aha_out); free(aha_out); free(description); + free(filename); - snprintf(buffer, 4096, "
\n"); - if (len + strlen(buffer) > max_len - 1) { - max_len += 4096; - page = (char *)realloc(page, max_len); - } - strcat(page, buffer); - len += strlen(buffer); + stralloc_cats(&page, "\n"); + stralloc_0(&page); sqlite3_finalize(res); sqlite3_close(db); - return page; + return page.s; } char *www_files_areas() { - char *page; - int max_len; - int len; - char buffer[4096]; - int i; - int j; + stralloc page = EMPTY_STRALLOC; - page = (char *)malloz(4096); - max_len = 4096; - len = 0; - - sprintf(buffer, "

File Directories

\n"); - if (len + strlen(buffer) > max_len - 1) { - max_len += 4096; - page = (char *)realloc(page, max_len); - } - strcat(page, buffer); - len += strlen(buffer); - - for (i = 0; i < conf.file_directory_count; i++) { - if (conf.file_directories[i]->display_on_web) { - sprintf(buffer, "
%s
\n", conf.file_directories[i]->name); - if (len + strlen(buffer) > max_len - 1) { - max_len += 4096; - page = (char *)realloc(page, max_len); - } - strcat(page, buffer); - len += strlen(buffer); - for (j = 0; j < conf.file_directories[i]->file_sub_count; j++) { - sprintf(buffer, "
%s
\n", conf.www_url, i, j, conf.file_directories[i]->file_subs[j]->name); - if (len + strlen(buffer) > max_len - 1) { - max_len += 4096; - page = (char *)realloc(page, max_len); - } - strcat(page, buffer); - len += strlen(buffer); - } + stralloc_copys(&page, "

File Directories

\n"); + for (int i = 0; i < conf.file_directory_count; i++) { + if (!conf.file_directories[i]->display_on_web) + continue; + stralloc_cats(&page, "
"); + stralloc_cats(&page, conf.file_directories[i]->name); + stralloc_cats(&page, "
\n"); + for (int j = 0; j < conf.file_directories[i]->file_sub_count; j++) { + stralloc_cats(&page, "
"); + stralloc_cats(&page, conf.file_directories[i]->file_subs[j]->name); + stralloc_cats(&page, "
\n"); } } + stralloc_0(&page); - return page; + return page.s; } char *www_files_get_from_area(int dir, int sub, char *clean_file) { char *sql = "SELECT filename FROM files WHERE approved=1 AND filename LIKE ? ESCAPE \"^\""; - char *filenamelike; + stralloc filenamelike = EMPTY_STRALLOC; sqlite3 *db; sqlite3_stmt *res; int rc; - char buffer[PATH_MAX]; + char pathbuf[PATH_MAX]; char *ret = NULL; int i; int extra = 0; @@ -475,67 +418,35 @@ char *www_files_get_from_area(int dir, int sub, char *clean_file) { char *file; file = www_decode(clean_file); - - for (i = 0; i < strlen(file); i++) { - if (file[i] == '^' || file[i] == '%' || file[i] == '_') { - extra++; - } + stralloc_copys(&filenamelike, "%"); + for (char *p = file; *p != '\0'; ++p) { + if (*p == '^' || *p == '_' || *p == '%') + stralloc_append1(&filenamelike, '^'); + stralloc_append1(&filenamelike, *p); } - - filenamelike = (char *)malloz(strlen(file) + 3 + extra); - - i = 0; - filenamelike[i++] = '%'; - filenamelike[i] = '\0'; - - for (j = 0; j < strlen(file); j++) { - switch (file[j]) { - case '^': - filenamelike[i++] = '^'; - filenamelike[i++] = '^'; - filenamelike[i] = '\0'; - break; - case '_': - filenamelike[i++] = '^'; - filenamelike[i++] = '_'; - filenamelike[i] = '\0'; - break; - case '%': - filenamelike[i++] = '^'; - filenamelike[i++] = '%'; - filenamelike[i] = '\0'; - break; - default: - filenamelike[i++] = file[j]; - filenamelike[i] = '\0'; - break; - } - } - - // sprintf(filenamelike, "%%/%s", file); - + stralloc_0(&filenamelike); free(file); - snprintf(buffer, PATH_MAX, "%s/%s.sq3", conf.bbs_path, conf.file_directories[dir]->file_subs[sub]->database); - - rc = sqlite3_open(buffer, &db); + snprintf(pathbuf, PATH_MAX, "%s/%s.sq3", conf.bbs_path, conf.file_directories[dir]->file_subs[sub]->database); + rc = sqlite3_open(pathbuf, &db); if (rc != SQLITE_OK) { + free(filenamelike.s); return NULL; } sqlite3_busy_timeout(db, 5000); rc = sqlite3_prepare_v2(db, sql, -1, &res, 0); if (rc != SQLITE_OK) { sqlite3_close(db); + free(filenamelike.s); return NULL; } - sqlite3_bind_text(res, 1, filenamelike, -1, 0); - + sqlite3_bind_text(res, 1, filenamelike.s, -1, 0); rc = sqlite3_step(res); if (rc == SQLITE_ROW) { ret = strdup(sqlite3_column_text(res, 0)); } - free(filenamelike); + free(filenamelike.s); sqlite3_finalize(res); sqlite3_close(db); return ret;