diff --git a/src/sbbs3/addfiles.c b/src/sbbs3/addfiles.c index 1ed3b4866d232c660752bf5bfcccd95f52c78bff..b4df267505d2d85db8b93b44c04516224f5260e5 100644 --- a/src/sbbs3/addfiles.c +++ b/src/sbbs3/addfiles.c @@ -245,7 +245,7 @@ void addlist(char *inpath, uint dirnum, const char* uploader, uint dskip, uint s reupload(&smb, &f); } else - result = smb_addfile(&smb, &f, SMB_SELFPACK, ext_desc, filepath); + result = smb_addfile(&smb, &f, SMB_SELFPACK, ext_desc, NULL, filepath); smb_freefilemem(&f); if(result != SMB_SUCCESS) fprintf(stderr, "!Error %d (%s) adding file to %s", result, smb.last_error, smb.file); @@ -415,7 +415,7 @@ void addlist(char *inpath, uint dirnum, const char* uploader, uint dskip, uint s reupload(&smb, &f); } else - result = smb_addfile(&smb, &f, SMB_SELFPACK, ext_desc, filepath); + result = smb_addfile(&smb, &f, SMB_SELFPACK, ext_desc, NULL, filepath); smb_freefilemem(&f); if(result != SMB_SUCCESS) fprintf(stderr, "!ERROR %d (%s) writing to %s\n" @@ -795,7 +795,7 @@ int main(int argc, char **argv) result = smb_updatemsg(&smb, &f); } else - result = smb_addfile(&smb, &f, SMB_SELFPACK, ext_desc, str); + result = smb_addfile(&smb, &f, SMB_SELFPACK, ext_desc, NULL, str); if(mode&UL_STATS) updatestats(l); files++; diff --git a/src/sbbs3/filedat.c b/src/sbbs3/filedat.c index 298842dbf8d2be1b580b6d8c07c1aa9012889853..440ac762febb5ad1f1203eb2815b2d92e2f4214c 100644 --- a/src/sbbs3/filedat.c +++ b/src/sbbs3/filedat.c @@ -29,6 +29,7 @@ #include "load_cfg.h" // smb_open_dir() #include "scfglib.h" #include "sauce.h" +#include "crc32.h" /* libarchive: */ #include <archive.h> @@ -636,8 +637,11 @@ bool addfile(scfg_t* cfg, uint dirnum, file_t* f, const char* extdesc, client_t* getfilepath(cfg, f, fpath); file_client_hfields(f, client); - int result = smb_addfile(&smb, f, SMB_SELFPACK, extdesc, fpath); + str_list_t list = list_archive_contents(fpath, /* pattern: */NULL + ,(cfg->dir[dirnum]->misc & DIR_NOHASH) == 0, /* error: */NULL, /* size: */0); + int result = smb_addfile_withlist(&smb, f, SMB_SELFPACK, extdesc, list, fpath); smb_close(&smb); + strListFree(&list); return result == SMB_SUCCESS; } @@ -698,6 +702,108 @@ int archive_type(const char* archive, char* str, size_t size) return result; } +str_list_t list_archive_contents(const char* filename, const char* pattern, bool hash, char* error, size_t maxerrlen) +{ + int result; + struct archive *ar; + struct archive_entry *entry; + + if((ar = archive_read_new()) == NULL) { + safe_snprintf(error, maxerrlen, "archive_read_new() returned NULL"); + return NULL; + } + archive_read_support_filter_all(ar); + archive_read_support_format_all(ar); + if((result = archive_read_open_filename(ar, filename, 10240)) != ARCHIVE_OK) { + safe_snprintf(error, maxerrlen, "archive_read_open_filename() returned %d: %s" + ,result, archive_error_string(ar)); + archive_read_free(ar); + return NULL; + } + + str_list_t list = strListInit(); + if(list == NULL) { + safe_snprintf(error, maxerrlen, "strListInit() returned NULL"); + archive_read_free(ar); + return NULL; + } + + while(1) { + result = archive_read_next_header(ar, &entry); + if(result != ARCHIVE_OK) { + if(result != ARCHIVE_EOF) { + safe_snprintf(error, maxerrlen, "archive_read_next_header() returned %d: %s" + ,result, archive_error_string(ar)); + archive_read_free(ar); + strListFree(&list); + return NULL; + } + break; + } + + const char* pathname = archive_entry_pathname(entry); + if(pathname == NULL) + continue; + + if(pattern != NULL && *pattern && !wildmatch(pathname, pattern, /* path: */false, /* case-sensitive: */false)) + continue; + + const char* type; + switch(archive_entry_filetype(entry)) { + case AE_IFREG: + type = "file"; + break; + case AE_IFLNK: + type = "link"; + break; + case AE_IFDIR: + type = "directory"; + break; + default: + continue; + } + + iniSetString(&list, pathname, "type", type, /* style: */NULL); + iniSetBytes(&list, pathname, "size", 1, archive_entry_size(entry), /* style: */NULL); + iniSetDateTime(&list, pathname, "time", true, archive_entry_mtime(entry), NULL); + iniSetInteger(&list, pathname, "mode", archive_entry_mode(entry), NULL); + iniSetString(&list, pathname, "format", archive_format_name(ar), NULL); + iniSetString(&list, pathname, "compression", archive_filter_name(ar, 0), NULL); + + if(hash && archive_entry_filetype(entry) == AE_IFREG) { + MD5 md5_ctx; + SHA1_CTX sha1_ctx; + uint8_t md5[MD5_DIGEST_SIZE]; + uint8_t sha1[SHA1_DIGEST_SIZE]; + uint32_t crc32 = 0; + + MD5_open(&md5_ctx); + SHA1Init(&sha1_ctx); + + const void *buff; + size_t size; + la_int64_t offset; + + for(;;) { + result = archive_read_data_block(ar, &buff, &size, &offset); + if(result != ARCHIVE_OK) + break; + crc32 = crc32i(~crc32, buff, size); + MD5_digest(&md5_ctx, buff, size); + SHA1Update(&sha1_ctx, buff, size); + } + MD5_close(&md5_ctx, md5); + SHA1Final(&sha1_ctx, sha1); + iniSetHexInt(&list, pathname, "crc32", crc32, NULL); + char hex[128]; + iniSetString(&list, pathname, "md5", MD5_hex(hex, md5), NULL); + iniSetString(&list, pathname, "sha1", SHA1_hex(hex, sha1), NULL); + } + } + archive_read_free(ar); + return list; +} + str_list_t directory(const char* path) { int flags = GLOB_MARK; diff --git a/src/sbbs3/filedat.h b/src/sbbs3/filedat.h index c478d93436201030b66cd374dfdaed170fd62c50..0f96a15f5179664401e20cc1ec4562209ed6b8c2 100644 --- a/src/sbbs3/filedat.h +++ b/src/sbbs3/filedat.h @@ -67,6 +67,7 @@ DLLEXPORT int file_sauce_hfields(file_t*, struct sauce_charinfo*); DLLEXPORT str_list_t directory(const char* path); DLLEXPORT long create_archive(const char* archive, const char* format ,bool with_path, str_list_t file_list, char* error, size_t maxerrlen); +DLLEXPORT str_list_t list_archive_contents(const char* archive, const char* pattern, bool hash, char* error, size_t maxerrlen); DLLEXPORT char* cmdstr(scfg_t*, user_t*, const char* instr, const char* fpath, const char* fspec, char* cmd, size_t); DLLEXPORT long extract_files_from_archive(const char* archive, const char* outdir, const char* allowed_filename_chars ,bool with_path, long max_files, str_list_t file_list, char* error, size_t); diff --git a/src/sbbs3/js_filebase.c b/src/sbbs3/js_filebase.c index a093f139b955591b1668178fc072a8f87576b55b..c43123f31a81a871e48d7cf27abe1932d2942ecd 100644 --- a/src/sbbs3/js_filebase.c +++ b/src/sbbs3/js_filebase.c @@ -164,6 +164,51 @@ js_dump_file(JSContext *cx, uintN argc, jsval *arglist) return JS_TRUE; } +static bool +set_content_properties(JSContext *cx, JSObject* obj, const char* fname, str_list_t ini) +{ + const char* val; + jsval js_val; + JSString* js_str; + const char* key; + const uintN flags = JSPROP_ENUMERATE | JSPROP_READONLY; + + if(fname == NULL + || (js_str = JS_NewStringCopyZ(cx, fname)) == NULL + || !JS_DefineProperty(cx, obj, "name", STRING_TO_JSVAL(js_str), NULL, NULL, flags)) + return false; + + const char* key_list[] = { "type", "time", "format", "compression", "md5", "sha1", NULL }; + for(size_t i = 0; key_list[i] != NULL; i++) { + key = key_list[i]; + if((val = iniGetString(ini, NULL, key, NULL, NULL)) != NULL + && ((js_str = JS_NewStringCopyZ(cx, val)) == NULL + || !JS_DefineProperty(cx, obj, key, STRING_TO_JSVAL(js_str), NULL, NULL, flags))) + return false; + } + + key = "size"; + js_val = DOUBLE_TO_JSVAL((jsdouble)iniGetBytes(ini, NULL, key, 1, -1)); + if(!JS_DefineProperty(cx, obj, key, js_val, NULL, NULL, flags)) + return false; + + key = "mode"; + if(iniKeyExists(ini, NULL, key)) { + js_val = INT_TO_JSVAL(iniGetInteger(ini, NULL, key, 0)); + if(!JS_DefineProperty(cx, obj, key, js_val, NULL, NULL, flags)) + return false; + } + + key = "crc32"; + if(iniKeyExists(ini, NULL, key)) { + js_val = UINT_TO_JSVAL(iniGetLongInt(ini, NULL, key, 0)); + if(!JS_DefineProperty(cx, obj, key, js_val, NULL, NULL, flags)) + return false; + } + + return true; +} + static bool set_file_properties(JSContext *cx, JSObject* obj, file_t* f, enum file_detail detail) { @@ -181,67 +226,67 @@ set_file_properties(JSContext *cx, JSObject* obj, file_t* f, enum file_detail de || !JS_DefineProperty(cx, obj, "name", STRING_TO_JSVAL(js_str), NULL, NULL, flags)) return false; - if(((f->from != NULL && *f->from != '\0') || detail > file_detail_extdesc) + if(((f->from != NULL && *f->from != '\0') || detail > file_detail_content) && ((js_str = JS_NewStringCopyZ(cx, f->from)) == NULL || !JS_DefineProperty(cx, obj, "from", STRING_TO_JSVAL(js_str), NULL, NULL, flags))) return false; - if(((f->from_ip != NULL && *f->from_ip != '\0') || detail > file_detail_extdesc) + if(((f->from_ip != NULL && *f->from_ip != '\0') || detail > file_detail_content) && ((js_str = JS_NewStringCopyZ(cx, f->from_ip)) == NULL || !JS_DefineProperty(cx, obj, "from_ip_addr", STRING_TO_JSVAL(js_str), NULL, NULL, flags))) return false; - if(((f->from_host != NULL && *f->from_host != '\0') || detail > file_detail_extdesc) + if(((f->from_host != NULL && *f->from_host != '\0') || detail > file_detail_content) && ((js_str = JS_NewStringCopyZ(cx, f->from_host)) == NULL || !JS_DefineProperty(cx, obj, "from_host_name", STRING_TO_JSVAL(js_str), NULL, NULL, flags))) return false; - if(((f->from_prot != NULL && *f->from_prot != '\0') || detail > file_detail_extdesc) + if(((f->from_prot != NULL && *f->from_prot != '\0') || detail > file_detail_content) && ((js_str = JS_NewStringCopyZ(cx, f->from_prot)) == NULL || !JS_DefineProperty(cx, obj, "from_protocol", STRING_TO_JSVAL(js_str), NULL, NULL, flags))) return false; - if(((f->from_port != NULL && *f->from_port != '\0') || detail > file_detail_extdesc) + if(((f->from_port != NULL && *f->from_port != '\0') || detail > file_detail_content) && ((js_str = JS_NewStringCopyZ(cx, f->from_port)) == NULL || !JS_DefineProperty(cx, obj, "from_port", STRING_TO_JSVAL(js_str), NULL, NULL, flags))) return false; - if(((f->author != NULL && *f->author != '\0') || detail > file_detail_extdesc) + if(((f->author != NULL && *f->author != '\0') || detail > file_detail_content) && ((js_str = JS_NewStringCopyZ(cx, f->author)) == NULL || !JS_DefineProperty(cx, obj, "author", STRING_TO_JSVAL(js_str), NULL, NULL, flags))) return false; - if(((f->author_org != NULL && *f->author_org != '\0') || detail > file_detail_extdesc) + if(((f->author_org != NULL && *f->author_org != '\0') || detail > file_detail_content) && ((js_str = JS_NewStringCopyZ(cx, f->author_org)) == NULL || !JS_DefineProperty(cx, obj, "author_org", STRING_TO_JSVAL(js_str), NULL, NULL, flags))) return false; - if(((f->to_list != NULL && *f->to_list != '\0') || detail > file_detail_extdesc) + if(((f->to_list != NULL && *f->to_list != '\0') || detail > file_detail_content) && ((js_str = JS_NewStringCopyZ(cx, f->to_list)) == NULL || !JS_DefineProperty(cx, obj, "to_list", STRING_TO_JSVAL(js_str), NULL, NULL, flags))) return false; val = BOOLEAN_TO_JSVAL(f->idx.attr & FILE_ANONYMOUS); - if((val == JSVAL_TRUE || detail > file_detail_extdesc) + if((val == JSVAL_TRUE || detail > file_detail_content) && !JS_DefineProperty(cx, obj, "anon", val, NULL, NULL, flags)) return false; - if(((f->tags != NULL && *f->tags != '\0') || detail > file_detail_extdesc) + if(((f->tags != NULL && *f->tags != '\0') || detail > file_detail_content) && ((js_str = JS_NewStringCopyZ(cx, f->tags)) == NULL || !JS_DefineProperty(cx, obj, "tags", STRING_TO_JSVAL(js_str), NULL, NULL, flags))) return false; - if(((f->desc != NULL && *f->desc != '\0') || detail > file_detail_extdesc) + if(((f->desc != NULL && *f->desc != '\0') || detail > file_detail_content) && ((js_str = JS_NewStringCopyZ(cx, f->desc)) == NULL || !JS_DefineProperty(cx, obj, "desc", STRING_TO_JSVAL(js_str), NULL, NULL, flags))) return false; - if(((f->extdesc != NULL && *f->extdesc != '\0') || detail > file_detail_extdesc) + if(((f->extdesc != NULL && *f->extdesc != '\0') || detail > file_detail_content) && ((js_str = JS_NewStringCopyZ(cx, f->extdesc)) == NULL || !JS_DefineProperty(cx, obj, "extdesc", STRING_TO_JSVAL(js_str), NULL, NULL, flags))) return false; - if(f->cost > 0 || detail > file_detail_extdesc) { + if(f->cost > 0 || detail > file_detail_content) { val = UINT_TO_JSVAL(f->cost); if(!JS_DefineProperty(cx, obj, "cost", val, NULL, NULL, flags)) return false; @@ -253,17 +298,17 @@ set_file_properties(JSContext *cx, JSObject* obj, file_t* f, enum file_detail de val = UINT_TO_JSVAL(f->hdr.when_written.time); if(!JS_DefineProperty(cx, obj, "time", val, NULL, NULL, flags)) return false; - if(f->hdr.when_imported.time > 0 || detail > file_detail_extdesc) { + if(f->hdr.when_imported.time > 0 || detail > file_detail_content) { val = UINT_TO_JSVAL(f->hdr.when_imported.time); if(!JS_DefineProperty(cx, obj, "added", val, NULL, NULL, flags)) return false; } - if(f->hdr.last_downloaded > 0 || detail > file_detail_extdesc) { + if(f->hdr.last_downloaded > 0 || detail > file_detail_content) { val = UINT_TO_JSVAL(f->hdr.last_downloaded); if(!JS_DefineProperty(cx, obj, "last_downloaded", val, NULL, NULL, flags)) return false; } - if(f->hdr.times_downloaded > 0 || detail > file_detail_extdesc) { + if(f->hdr.times_downloaded > 0 || detail > file_detail_content) { val = UINT_TO_JSVAL(f->hdr.times_downloaded); if(!JS_DefineProperty(cx, obj, "times_downloaded", val, NULL, NULL, flags)) return false; @@ -291,6 +336,32 @@ set_file_properties(JSContext *cx, JSObject* obj, file_t* f, enum file_detail de return false; } + if(detail >= file_detail_content) { + JSObject* array; + if((array = JS_NewArrayObject(cx, 0, NULL)) == NULL) { + JS_ReportError(cx, "array allocation failure, line %d", __LINE__); + return false; + } + str_list_t ini = strListSplit(NULL, f->content, "\r\n"); + str_list_t file_list = iniGetSectionList(ini, NULL); + if(file_list != NULL) { + for(size_t i = 0; file_list[i] != NULL; i++) { + JSObject* fobj; + if((fobj = JS_NewObject(cx, NULL, NULL, array)) == NULL) { + JS_ReportError(cx, "object allocation failure, line %d", __LINE__); + return false; + } + str_list_t section = iniGetSection(ini, file_list[i]); + set_content_properties(cx, fobj, file_list[i], section); + JS_DefineElement(cx, array, i, OBJECT_TO_JSVAL(fobj), NULL, NULL, JSPROP_ENUMERATE); + iniFreeStringList(section); + } + strListFree(&file_list); + } + strListFree(&ini); + JS_DefineProperty(cx, obj, "content", OBJECT_TO_JSVAL(array), NULL, NULL, JSPROP_ENUMERATE); + } + return true; } @@ -1164,7 +1235,10 @@ js_add_file(JSContext *cx, uintN argc, jsval *arglist) char fpath[MAX_PATH + 1]; getfilepath(scfg, &file, fpath); file_client_hfields(&file, client); - p->smb_result = smb_addfile(&p->smb, &file, SMB_SELFPACK, extdesc, fpath); + str_list_t list = list_archive_contents(fpath, /* pattern: */NULL + ,(scfg->dir[file.dir]->misc & DIR_NOHASH) == 0, /* error: */NULL, /* size: */0); + p->smb_result = smb_addfile_withlist(&p->smb, &file, SMB_SELFPACK, extdesc, list, fpath); + strListFree(&list); JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(p->smb_result == SMB_SUCCESS)); } JS_RESUMEREQUEST(cx, rc); @@ -1246,8 +1320,13 @@ js_update_file(JSContext *cx, uintN argc, jsval *arglist) if(strcmp(extdesc ? extdesc : "", file.extdesc ? file.extdesc : "") == 0) p->smb_result = smb_putfile(&p->smb, &file); else { - if((p->smb_result = smb_removefile(&p->smb, &file)) == SMB_SUCCESS) - p->smb_result = smb_addfile(&p->smb, &file, SMB_SELFPACK, extdesc, newfname); + if((p->smb_result = smb_removefile(&p->smb, &file)) == SMB_SUCCESS) { + str_list_t list = list_archive_contents(newfname, /* pattern: */NULL + ,file.dir < scfg->total_dirs && (scfg->dir[file.dir]->misc & DIR_NOHASH) == 0 + ,/* error: */NULL, /* size: */0); + p->smb_result = smb_addfile_withlist(&p->smb, &file, SMB_SELFPACK, extdesc, list, newfname); + strListFree(&list); + } } } } @@ -1749,6 +1828,7 @@ static char* filebase_detail_prop_desc[] = { "Include indexed-filenames only", "Normal level of file detail (e.g. full filenames, minimal meta data)", "Normal level of file detail plus extended descriptions", + "Normal level of file detail plus extended descriptions and archived contents", "Maximum file detail, include undefined/null property values", NULL }; @@ -1789,10 +1869,12 @@ JSObject* js_CreateFileBaseClass(JSContext* cx, JSObject* parent, scfg_t* cfg) , JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY); JS_DefineProperty(cx, detail, "EXTENDED", INT_TO_JSVAL(file_detail_extdesc), NULL, NULL , JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY); - JS_DefineProperty(cx, detail, "MAX", INT_TO_JSVAL(file_detail_extdesc + 1), NULL, NULL + JS_DefineProperty(cx, detail, "CONTENTS", INT_TO_JSVAL(file_detail_content), NULL, NULL + , JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY); + JS_DefineProperty(cx, detail, "MAX", INT_TO_JSVAL(file_detail_content + 1), NULL, NULL , JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY); #ifdef BUILD_JSDOCS - js_DescribeSyncObject(cx, detail, "Detail level numeric constants", 0); + js_DescribeSyncObject(cx, detail, "Detail level numeric constants (in increasing verbosity)", 0); js_CreateArrayOfStrings(cx, detail, "_property_desc_list", filebase_detail_prop_desc, JSPROP_READONLY); #endif } diff --git a/src/sbbs3/upgrade_to_v319.c b/src/sbbs3/upgrade_to_v319.c index a4f8cc9f98c08453729583e813afd09c34d5b46a..8c0d668fa3b89375329d82aabce96b538f2fd016 100644 --- a/src/sbbs3/upgrade_to_v319.c +++ b/src/sbbs3/upgrade_to_v319.c @@ -660,7 +660,10 @@ bool upgrade_file_bases(bool hash) if(*extdesc) body = extdesc; } - result = smb_addfile(&smb, &file, SMB_FASTALLOC, body, fpath); + str_list_t list = list_archive_contents(fpath, /* pattern: */NULL + ,(scfg.dir[i]->misc & DIR_NOHASH) == 0, /* error: */NULL, /* size: */0); + result = smb_addfile_withlist(&smb, &file, SMB_FASTALLOC, body, list, fpath); + strListFree(&list); } if(result != SMB_SUCCESS) { fprintf(stderr, "\n!Error %d (%s) adding file to %s\n", result, smb.last_error, smb.file); diff --git a/src/smblib/smbdefs.h b/src/smblib/smbdefs.h index 5f692adf18ecd154d36b320da603b1be7199f9ed..a91eea7dfc0e031d3f51005f97dfe76b3951b7dd 100644 --- a/src/smblib/smbdefs.h +++ b/src/smblib/smbdefs.h @@ -632,6 +632,10 @@ typedef struct { /* Message or File */ uchar* text; /* Message body text (optional) */ char* extdesc; /* File extended description */ }; + union { + uchar* tail; /* Message body tail (optional) */ + char* content; /* Archive content list */ + }; char* tags; /* Message tags (space-delimited) */ char* editor; /* Message editor (if known) */ char* mime_version; /* MIME Version (if applicable) */ diff --git a/src/smblib/smbfile.c b/src/smblib/smbfile.c index f96426376b6296018020188651aa42589ebeb5fc..da6cca6a1d3652db27e8b6bfde46c8e7b3241986 100644 --- a/src/smblib/smbfile.c +++ b/src/smblib/smbfile.c @@ -295,7 +295,9 @@ int smb_getfile(smb_t* smb, smbfile_t* file, enum file_detail detail) if((result = smb_getmsghdr(smb, file)) != SMB_SUCCESS) return result; if(detail >= file_detail_extdesc) - file->extdesc = smb_getmsgtxt(smb, file, GETMSGTXT_ALL); + file->extdesc = smb_getmsgtxt(smb, file, GETMSGTXT_BODY_ONLY); + if(detail >= file_detail_content) + file->content = smb_getmsgtxt(smb, file, GETMSGTXT_TAIL_ONLY); } file->dir = smb->dirnum; @@ -325,7 +327,7 @@ void smb_freefilemem(smbfile_t* file) /****************************************************************************/ /****************************************************************************/ -int smb_addfile(smb_t* smb, smbfile_t* file, int storage, const char* extdesc, const char* path) +int smb_addfile(smb_t* smb, smbfile_t* file, int storage, const char* extdesc, const char* content, const char* path) { if(file->name == NULL || *file->name == '\0') { safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s missing name", __FUNCTION__); @@ -343,7 +345,28 @@ int smb_addfile(smb_t* smb, smbfile_t* file, int storage, const char* extdesc, c } file->hdr.attr |= MSG_FILE; file->hdr.type = SMB_MSG_TYPE_FILE; - return smb_addmsg(smb, file, storage, SMB_HASH_SOURCE_NONE, XLAT_NONE, /* body: */(const uchar*)extdesc, /* tail: */NULL); + return smb_addmsg(smb, file, storage, SMB_HASH_SOURCE_NONE, XLAT_NONE + ,/* body: */(const uchar*)extdesc, /* tail: */(const uchar*)content); +} + +/****************************************************************************/ +/* Like smb_addfile(), except 'content' is a str_list_t: 'list' */ +/****************************************************************************/ +int smb_addfile_withlist(smb_t* smb, smbfile_t* file, int storage, const char* extdesc, str_list_t list, const char* path) +{ + char* content = NULL; + int result; + + if(list != NULL) { + size_t size = strListCount(list) * 1024; + content = calloc(1, size); + if(content == NULL) + return SMB_ERR_MEM; + strListCombine(list, content, size - 1, "\r\n"); + } + result = smb_addfile(smb, file, storage, extdesc, content, path); + free(content); + return result; } /****************************************************************************/ @@ -353,7 +376,7 @@ int smb_renewfile(smb_t* smb, smbfile_t* file, int storage, const char* path) int result; if((result = smb_removefile(smb, file)) != SMB_SUCCESS) return result; - return smb_addfile(smb, file, storage, file->extdesc, path); + return smb_addfile(smb, file, storage, file->extdesc, file->content, path); } /****************************************************************************/ diff --git a/src/smblib/smblib.c b/src/smblib/smblib.c index 0ddccff1edcc52a5c6e2b9b144fedbdd2660ae92..ab102772231e502b464d3c591e2b5b1dc6956ea9 100644 --- a/src/smblib/smblib.c +++ b/src/smblib/smblib.c @@ -1141,6 +1141,10 @@ void smb_freemsgmem(smbmsg_t* msg) free(msg->text); msg->text = NULL; } + if(msg->tail != NULL) { + free(msg->tail); + msg->tail = NULL; + } } /****************************************************************************/ diff --git a/src/smblib/smblib.h b/src/smblib/smblib.h index 660db76ff3cf01b313ed898af573cc99d2b85ca6..cb28c223c357a1be1cb5b7feadddc97dc94bdd5b 100644 --- a/src/smblib/smblib.h +++ b/src/smblib/smblib.h @@ -283,8 +283,9 @@ SMBEXPORT int smb_open_fp(smb_t*, FILE**, int share); SMBEXPORT void smb_close_fp(FILE**); /* New FileBase API: */ -enum file_detail { file_detail_index, file_detail_normal, file_detail_extdesc }; -SMBEXPORT int smb_addfile(smb_t*, smbfile_t*, int storage, const char* extdesc, const char* path); +enum file_detail { file_detail_index, file_detail_normal, file_detail_extdesc, file_detail_content }; +SMBEXPORT int smb_addfile(smb_t*, smbfile_t*, int storage, const char* extdesc, const char* content, const char* path); +SMBEXPORT int smb_addfile_withlist(smb_t*, smbfile_t*, int storage, const char* extdesc, str_list_t, const char* path); SMBEXPORT int smb_renewfile(smb_t*, smbfile_t*, int storage, const char* path); SMBEXPORT int smb_getfile(smb_t*, smbfile_t*, enum file_detail); SMBEXPORT int smb_putfile(smb_t*, smbfile_t*);