# HG changeset patch # User Carl Byington # Date 1239845982 25200 # Node ID 4b498fd68464ee83c776ae92c7a0ebc2ec0851a4 # Parent e3a63888cdd41220e0f648a78816c143088cdd0e add pst_attach_to_mem() back into the shared library interface. improve developer documentation. fix memory leak caught by valgrind. diff -r e3a63888cdd4 -r 4b498fd68464 ChangeLog --- a/ChangeLog Tue Apr 14 22:26:17 2009 -0700 +++ b/ChangeLog Wed Apr 15 18:39:42 2009 -0700 @@ -1,3 +1,9 @@ +LibPST 0.6.37 (2009-04-15) +=============================== + * add pst_attach_to_mem() back into the shared library interface. + * improve developer documentation. + * fix memory leak caught by valgrind. + LibPST 0.6.36 (2009-04-14) =============================== * spec file cleanup with multiple sub packages. diff -r e3a63888cdd4 -r 4b498fd68464 NEWS --- a/NEWS Tue Apr 14 22:26:17 2009 -0700 +++ b/NEWS Wed Apr 15 18:39:42 2009 -0700 @@ -1,3 +1,4 @@ +0.6.37 2009-04-15 add pst_attach_to_mem() back into the shared library interface. 0.6.36 2009-04-14 build separate -doc and -devel-doc subpackages 0.6.35 2009-04-08 properly add trailing mime boundary in all modes, build separate rpms with libpst.so shared. 0.6.34 2009-03-19 avoid putting mixed item types into the same output folder diff -r e3a63888cdd4 -r 4b498fd68464 configure.in --- a/configure.in Tue Apr 14 22:26:17 2009 -0700 +++ b/configure.in Wed Apr 15 18:39:42 2009 -0700 @@ -1,5 +1,5 @@ AC_PREREQ(2.59) -AC_INIT(libpst,0.6.36,carl@five-ten-sg.com) +AC_INIT(libpst,0.6.37,carl@five-ten-sg.com) AC_CONFIG_SRCDIR([src/libpst.c]) AC_CONFIG_HEADER([config.h]) AM_INIT_AUTOMAKE @@ -19,7 +19,7 @@ # 6. libtool will build libpst.so.x.y.z where the SONAME is libpst.so.x # and x=current-age, y=age, z=revision -libpst_version_info='2:0:0' +libpst_version_info='3:0:1' AC_SUBST(LIBPST_VERSION_INFO, [$libpst_version_info]) libpst_so_major='2' AC_SUBST(LIBPST_SO_MAJOR, [$libpst_so_major]) @@ -27,7 +27,7 @@ # libpst # version soname so library name # 0.6.35 libpst.so.2 libpst.so.2.0.0 - +# 0.6.37 libpst.so.2 libpst.so.2.1.0 diff -r e3a63888cdd4 -r 4b498fd68464 libpst.spec.in --- a/libpst.spec.in Tue Apr 14 22:26:17 2009 -0700 +++ b/libpst.spec.in Wed Apr 15 18:39:42 2009 -0700 @@ -125,6 +125,10 @@ %changelog +* Wed Apr 15 2009 Carl Byington - 0.6.37-1 +- add pst_attach_to_mem() back into the shared library interface. +- fix memory leak caught by valgrind. + * Tue Apr 14 2009 Carl Byington - 0.6.36-1 - build separate -doc and -devel-doc subpackages. - other spec file cleanup diff -r e3a63888cdd4 -r 4b498fd68464 regression/regression-tests.bash --- a/regression/regression-tests.bash Tue Apr 14 22:26:17 2009 -0700 +++ b/regression/regression-tests.bash Wed Apr 15 18:39:42 2009 -0700 @@ -65,7 +65,7 @@ val="valgrind --leak-check=full" -val='' +#val='' pushd .. make || exit diff -r e3a63888cdd4 -r 4b498fd68464 src/libpst.c --- a/src/libpst.c Tue Apr 14 22:26:17 2009 -0700 +++ b/src/libpst.c Wed Apr 15 18:39:42 2009 -0700 @@ -17,7 +17,6 @@ #pragma pack(1) #endif - #define ASSERT(x) { if(!(x)) raise( SIGSEGV ); } #define INDEX_TYPE32 0x0E @@ -448,7 +447,7 @@ } else if (node->parent_d_id == node->d_id) { // add top level node to the descriptor tree - DEBUG_INDEX(("%#"PRIx64" is its own parent. What is this world coming to?\n")); + DEBUG_INDEX(("%#"PRIx64" is its own parent. What is this world coming to?\n", node->d_id)); add_descriptor_to_list(node, &pf->d_head, &pf->d_tail); } else { //DEBUG_INDEX(("Searching for parent %#"PRIx64" of %#"PRIx64"\n", node->parent_d_id, node->d_id)); @@ -520,6 +519,28 @@ } +size_t pst_attach_to_mem(pst_file *pf, pst_item_attach *attach, char **b) { + pst_index_ll *ptr; + pst_holder h = {b, NULL, 0}; + size_t size = 0; + DEBUG_ENT("pst_attach_to_mem"); + if (attach->i_id != (uint64_t)-1) { + ptr = pst_getID(pf, attach->i_id); + if (ptr) { + size = pst_ff_getID2data(pf, ptr, &h); + } else { + DEBUG_WARN(("Couldn't find ID pointer. Cannot handle attachment\n")); + } + attach->data.size = size; + } else { + size = attach->data.size; + *b = attach->data.data; + } + DEBUG_RET(); + return size; +} + + size_t pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE* fp) { pst_index_ll *ptr; pst_holder h = {NULL, fp, 0}; @@ -558,12 +579,12 @@ attach->data.size = size; } else { // encode the attachment to the file - char *c = pst_base64_encode(attach->data.data, attach->data.size); + size = attach->data.size; + char *c = pst_base64_encode(attach->data.data, size); if (c) { (void)pst_fwrite(c, (size_t)1, strlen(c), fp); free(c); // caught by valgrind } - size = attach->data.size; } DEBUG_RET(); return size; @@ -686,7 +707,6 @@ xattrib.map = PST_LE_GET_UINT16(buffer+bptr), bptr += 2; ptr = (pst_x_attrib_ll*) pst_malloc(sizeof(*ptr)); memset(ptr, 0, sizeof(*ptr)); - ptr->type = xattrib.type; ptr->map = xattrib.map+0x8000; ptr->next = NULL; DEBUG_INDEX(("xattrib: ext = %#"PRIx32", type = %#"PRIx16", map = %#"PRIx16"\n", @@ -1262,20 +1282,18 @@ pst_free_list(list); // now we will have initial information of each attachment stored in item->attach... - // we must now read the secondary record for each based on the id2 val associated with + // we must now read the secondary record for each based on the id2_val associated with // each attachment - attach = item->attach; - while (attach) { + for (attach = item->attach; attach; attach = attach->next) { DEBUG_WARN(("initial attachment id2 %#"PRIx64"\n", attach->id2_val)); if ((id2_ptr = pst_getID2(id2_head, attach->id2_val))) { DEBUG_WARN(("initial attachment id2 found id %#"PRIx64"\n", id2_ptr->id->i_id)); - // id_ptr is a record describing the attachment + // id2_ptr is a record describing the attachment // we pass NULL instead of id2_head cause we don't want it to // load all the extra stuff here. list = pst_parse_block(pf, id2_ptr->id->i_id, NULL); if (!list) { DEBUG_WARN(("ERROR error processing an attachment record\n")); - attach = attach->next; continue; } if (list->count_objects > 1) { @@ -1284,7 +1302,6 @@ if (pst_process(list, item, attach)) { DEBUG_WARN(("ERROR pst_process() failed with an attachment\n")); pst_free_list(list); - attach = attach->next; continue; } pst_free_list(list); @@ -1302,7 +1319,6 @@ DEBUG_WARN(("ERROR cannot locate id2 value %#"PRIx64"\n", attach->id2_val)); attach->id2_val = 0; // suppress this missing attachment } - attach = attach->next; } } @@ -2080,10 +2096,10 @@ if (list->elements[x]->extra) { pst_item_extra_field *ef = (pst_item_extra_field*) pst_malloc(sizeof(pst_item_extra_field)); memset(ef, 0, sizeof(pst_item_extra_field)); - ef->field_name = strdup(list->elements[x]->extra); LIST_COPY_CSTR(ef->value); if (ef->value) { - ef->next = item->extra_fields; + ef->field_name = strdup(list->elements[x]->extra); + ef->next = item->extra_fields; item->extra_fields = ef; DEBUG_EMAIL(("Extra Field - \"%s\" = \"%s\"\n", ef->field_name, ef->value)); if (strcmp(ef->field_name, "content-type") == 0) { @@ -2106,6 +2122,7 @@ else { DEBUG_EMAIL(("What does this mean? Internet header %s value\n", list->elements[x]->extra)); DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size); + free(ef); // caught by valgrind } } break; @@ -3808,8 +3825,7 @@ /** - * Get an ID block from file using _pst_ff_getIDblock and decrypt if necessary - * + * Get an ID block from file using pst_ff_getIDblock() and decrypt if necessary * @param pf PST file structure * @param i_id ID of block to retrieve * @param buf reference to pointer to buffer that will contain the data block. @@ -4085,52 +4101,48 @@ char *ret, *a, *b; size_t x = 0; int y, z; + if (!str) return NULL; DEBUG_ENT("rfc2426_escape"); - if (!str) + // calculate space required to escape all the following characters + y = pst_chr_count(str, ',') + + pst_chr_count(str, '\\') + + pst_chr_count(str, ';') + + pst_chr_count(str, '\n'); + z = pst_chr_count(str, '\r'); + if (y == 0 && z == 0) + // there isn't any extra space required ret = str; else { - - // calculate space required to escape all the following characters - y = pst_chr_count(str, ',') - + pst_chr_count(str, '\\') - + pst_chr_count(str, ';') - + pst_chr_count(str, '\n'); - z = pst_chr_count(str, '\r'); - if (y == 0 && z == 0) - // there isn't any extra space required - ret = str; - else { - x = strlen(str) + y - z + 1; // don't forget room for the NUL - if (x > buflen) { - buf = (char*) realloc(buf, x); - buflen = x; + x = strlen(str) + y - z + 1; // don't forget room for the NUL + if (x > buflen) { + buf = (char*) realloc(buf, x); + buflen = x; + } + a = str; + b = buf; + while (*a != '\0') { + switch (*a) { + case ',' : + case '\\': + case ';' : + *(b++) = '\\'; + *b = *a; + break; + case '\n': // newlines are encoded as "\n" + *(b++) = '\\'; + *b = 'n'; + break; + case '\r': // skip cr + b--; + break; + default: + *b=*a; } - a = str; - b = buf; - while (*a != '\0') { - switch (*a) { - case ',' : - case '\\': - case ';' : - *(b++) = '\\'; - *b = *a; - break; - case '\n': // newlines are encoded as "\n" - *(b++) = '\\'; - *b = 'n'; - break; - case '\r': // skip cr - b--; - break; - default: - *b=*a; - } - b++; - a++; - } - *b = '\0'; // NUL-terminate the string (buf) - ret = buf; + b++; + a++; } + *b = '\0'; // NUL-terminate the string (buf) + ret = buf; } DEBUG_RET(); return ret; diff -r e3a63888cdd4 -r 4b498fd68464 src/libpst.h --- a/src/libpst.h Tue Apr 14 22:26:17 2009 -0700 +++ b/src/libpst.h Wed Apr 15 18:39:42 2009 -0700 @@ -681,7 +681,9 @@ } pst_item_appointment; -/** This contains the common mapi elements, and pointers to structures for each major mapi item type */ +/** This contains the common mapi elements, and pointers to structures for + * each major mapi item type. It represents a complete mapi object. + */ typedef struct pst_item { /** email mapi elements */ pst_item_email *email; @@ -760,12 +762,26 @@ } pst_item; -/** linked list of extended attributes */ +/** Linked list of extended attributes. + * This is used to convert mapi_id values in the pst file into + * cannonical mapi_id values to be used in this code. This list + * is kept in sorted order, where the key is the 'map' field. + * Some mapi_id values are converted to cannonical mapi_id values + * (PST_MAP_ATTRIB), and others are converted to a string + * (PST_ATTRIB_HEADER). + */ typedef struct pst_x_attrib_ll { + /** obsolete field, this is now unused */ uint32_t type; + /** @li 1 PST_MAP_ATTRIB map->int attribute + @li 2 PST_MAP_HEADER map->string header + */ uint32_t mytype; + /** key for the mapping */ uint32_t map; - void *data; + /** data target of the mapping, either uint32_t or string */ + void *data; + /** link to next item in the list */ struct pst_x_attrib_ll *next; } pst_x_attrib_ll; @@ -819,30 +835,171 @@ } pst_file; +/** Open a pst file. + * @param pf pointer to uninitialized pst_file structure. This structure + * will be filled in by this function. + * @param name name of the file, suitable for fopen(). + * @return 0 if ok, -1 if error + */ int pst_open(pst_file *pf, char *name); -int pst_close(pst_file *pf); -pst_desc_tree* pst_getTopOfFolders(pst_file *pf, pst_item *root); -size_t pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE* fp); -size_t pst_attach_to_file_base64(pst_file *pf, pst_item_attach *attach, FILE* fp); + + +/** Load the index entries from the pst file. This loads both the + * i_id linked list, and the d_id tree, and should normally be the + * first call after pst_open(). + * @param pf pointer to the pst_file structure setup by pst_open(). + */ int pst_load_index (pst_file *pf); -pst_desc_tree* pst_getNextDptr(pst_desc_tree* d); + + +/** Load the extended attribute mapping table from the pst file. This + * should normally be the second call after pst_open(). + * @param pf pointer to the pst_file structure setup by pst_open(). + */ int pst_load_extended_attributes(pst_file *pf); -pst_item* pst_getItem(pst_file *pf, pst_desc_tree *d_ptr); + + +/** Close a pst file. + * @param pf pointer to the pst_file structure setup by pst_open(). + */ +int pst_close(pst_file *pf); + + +/** Get the top of folders descriptor tree. This is the main descriptor tree + * that needs to be walked to look at every item in the pst file. + * @param pf pointer to the pst_file structure setup by pst_open(). + * @param root root item, which can be obtained by pst_parse_item(pf, pf->d.head, NULL). + */ +pst_desc_tree* pst_getTopOfFolders(pst_file *pf, pst_item *root); + + +/** Assemble the binary attachment into a single buffer. + * @param pf pointer to the pst_file structure setup by pst_open(). + * @param attach pointer to the attachment record + * @param b pointer to location to store the buffer pointer. The + * caller must free this buffer. + * @return size of the buffer, and return the buffer pointer in *b + */ +size_t pst_attach_to_mem(pst_file *pf, pst_item_attach *attach, char **b); + + +/** Write a binary attachment to a file. + * @param pf pointer to the pst_file structure setup by pst_open(). + * @param attach pointer to the attachment record + * @param fp pointer to an open FILE. + */ +size_t pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE* fp); + + +/** Write a binary attachment base64 encoded to a file. + * @param pf pointer to the pst_file structure setup by pst_open(). + * @param attach pointer to the attachment record + * @param fp pointer to an open FILE. + */ +size_t pst_attach_to_file_base64(pst_file *pf, pst_item_attach *attach, FILE* fp); + + +/** Walk the descriptor tree. + * @param d pointer to the current item in the descriptor tree. + * @return pointer to the next item in the descriptor tree. + */ +pst_desc_tree* pst_getNextDptr(pst_desc_tree* d); + + +/** Assemble a mapi object from a descriptor pointer. + * @param pf pointer to the pst_file structure setup by pst_open(). + * @param d_ptr pointer to an item in the descriptor tree. + * @param m_head normally NULL. This is only used when processing embedded + * attached rfc822 messages, in which case it is attach->id2_head. + * @return pointer to the mapi object. Must be free'd by pst_freeItem(). + */ pst_item* pst_parse_item (pst_file *pf, pst_desc_tree *d_ptr, pst_id2_tree *m_head); + + +/** Free the item returned by pst_parse_item(). + * @param item pointer to item returned from pst_parse_item(). + */ void pst_freeItem(pst_item *item); + + +/** Lookup the i_id in the index linked list, and return a pointer to the element. + * @param pf pointer to the pst_file structure setup by pst_open(). + * @param i_id key for the index linked list + * @return pointer to the element, or NULL if not found. + */ pst_index_ll* pst_getID(pst_file* pf, uint64_t i_id); -int pst_decrypt(uint64_t id, char *buf, size_t size, unsigned char type); -size_t pst_ff_getIDblock_dec(pst_file *pf, uint64_t id, char **b); -size_t pst_ff_getIDblock(pst_file *pf, uint64_t id, char** b); -size_t pst_fwrite(const void*ptr, size_t size, size_t nmemb, FILE*stream); + + +/** Decrypt a block of data from the pst file. + * @param i_id identifier of this block, needed as part of the key for the enigma cipher + * @param buf pointer to the buffer to be decrypted + * @param size size of the buffer + * @param type + @li 0 PST_NO_ENCRYPT, none + @li 1 PST_COMP_ENCRYPT, simple byte substitution cipher with fixed key + @li 2 PST_ENCRYPT, german enigma 3 rotor cipher with fixed key + * @return 0 if ok, -1 if error (NULL buffer or unknown encryption type) + */ +int pst_decrypt(uint64_t i_id, char *buf, size_t size, unsigned char type); + + +/** Get an ID block from the file using pst_ff_getIDblock() and decrypt if necessary. + * @param pf pointer to the pst_file structure setup by pst_open(). + * @param i_id ID of block to retrieve + * @param buf reference to pointer to buffer that will contain the data block. + * If this pointer is non-NULL, it will first be free()d. + * @return Size of block read into memory + */ +size_t pst_ff_getIDblock_dec(pst_file *pf, uint64_t i_id, char **buf); + + +/** Read a block of data from the file into memory. + * @param pf pointer to the pst_file structure setup by pst_open(). + * @param i_id ID of block to read + * @param buf reference to pointer to buffer that will contain the data block. + * If this pointer is non-NULL, it will first be free()d. + * @return size of block read into memory + */ +size_t pst_ff_getIDblock(pst_file *pf, uint64_t i_id, char** buf); + + +/** fwrite with checking for null pointer. + * @param ptr pointer to the buffer + * @param size size of each item + * @param nmemb number of items + * @param stream output file + * @return number of bytes written, zero if ptr==NULL + */ +size_t pst_fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream); + + +/** Add any necessary escape characters for rfc2426 vcard format + * @param str pointer to input string + * @return pointer to output string, either the input pointer if + * there are no characters that need escapes, or a pointer + * to a different buffer containing the escaped string. In + * either case, you don't need to free this returned pointer. + */ char * pst_rfc2426_escape(char *str); + + +/** Convert a FILETIME into rfc2425 date/time format 1953-10-15T23:10:00Z + * which is the same as one of the forms in the ISO3601 standard + * @param ft time to be converted + * @return time in rfc2425 format + */ char * pst_rfc2425_datetime_format(FILETIME *ft); + + +/** Convert a FILETIME into rfc2445 date/time format 19531015T231000Z + * @param ft time to be converted + * @return time in rfc2445 format + */ char * pst_rfc2445_datetime_format(FILETIME *ft); /** Convert a code page integer into a string suitable for iconv() - * - * @param cp the code page integer used in the pst file + * @param cp the code page integer used in the pst file * @return pointer to a static buffer holding the string representation of the * equivalent iconv character set */ @@ -858,7 +1015,6 @@ /** Convert str to utf8 if possible; null strings are preserved. - * * @param item pointer to the containing mapi item * @param str pointer to the mapi string of interest */ @@ -866,7 +1022,6 @@ /** Convert str to utf8 if possible; null strings are converted into empty strings. - * * @param item pointer to the containing mapi item * @param str pointer to the mapi string of interest */ diff -r e3a63888cdd4 -r 4b498fd68464 src/readpst.c --- a/src/readpst.c Tue Apr 14 22:26:17 2009 -0700 +++ b/src/readpst.c Wed Apr 15 18:39:42 2009 -0700 @@ -1100,7 +1100,6 @@ char sender[60]; int sender_known = 0; char *temp = NULL; - int attach_num; time_t em_time; char *c_time; char *headers = NULL; @@ -1347,7 +1346,7 @@ // other attachments { pst_item_attach* attach; - attach_num = 0; + int attach_num = 0; for (attach = item->attach; attach; attach = attach->next) { pst_convert_utf8_null(item, &attach->filename1); pst_convert_utf8_null(item, &attach->filename2); diff -r e3a63888cdd4 -r 4b498fd68464 xml/libpst.in --- a/xml/libpst.in Tue Apr 14 22:26:17 2009 -0700 +++ b/xml/libpst.in Wed Apr 15 18:39:42 2009 -0700 @@ -7,6 +7,8 @@ url="http://www.five-ten-sg.com/@PACKAGE@/packages/">http://www.five-ten-sg.com/@PACKAGE@/packages/. The most recent documentation is available at http://www.five-ten-sg.com/@PACKAGE@/. + The most recent developer documentation for the shared library is available at http://www.five-ten-sg.com/@PACKAGE@/devel/. A - 2009-03-11 + 2009-04-15 @@ -233,7 +235,7 @@ - 2009-03-11 + 2009-04-15 @@ -336,7 +338,7 @@ - 2009-03-11 + 2009-04-15 @@ -511,7 +513,7 @@ - 2009-03-11 + 2009-04-15 @@ -680,7 +682,7 @@ - 2009-03-11 + 2009-04-15 @@ -814,7 +816,7 @@ - 2009-03-11 + 2009-04-15