diff options
author | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
---|---|---|
committer | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
commit | 094ca96844842928810f14844413109fc6cdd890 (patch) | |
tree | e60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /pith/store.c | |
download | alpine-094ca96844842928810f14844413109fc6cdd890.tar.xz |
Initial Alpine Version
Diffstat (limited to 'pith/store.c')
-rw-r--r-- | pith/store.c | 1021 |
1 files changed, 1021 insertions, 0 deletions
diff --git a/pith/store.c b/pith/store.c new file mode 100644 index 00000000..e8508257 --- /dev/null +++ b/pith/store.c @@ -0,0 +1,1021 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: store.c 1074 2008-06-04 00:08:43Z hubert@u.washington.edu $"; +#endif + +/* + * ======================================================================== + * Copyright 2006-2008 University of Washington + * Copyright 2013 Eduardo Chappa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +/* + * GENERALIZED STORAGE FUNCTIONS. Idea is to allow creation of + * storage objects that can be written into and read from without + * the caller knowing if the storage is core or in a file + * or whatever. + */ + + +#include "../pith/headers.h" +#include "../pith/store.h" +#include "../pith/status.h" +#include "../pith/state.h" +#include "../pico/keydefs.h" +#ifdef SMIME +#include <openssl/buffer.h> +#endif /* SMIME */ + + +/* + * Internal prototypes + */ +void *so_file_open(STORE_S *); +int so_cs_writec(int, STORE_S *); +int so_cs_writec_locale(int, STORE_S *); +int so_file_writec(int, STORE_S *); +int so_file_writec_locale(int, STORE_S *); +int so_cs_readc(unsigned char *, STORE_S *); +int so_cs_readc_locale(unsigned char *, STORE_S *); +int so_cs_readc_getchar(unsigned char *c, void *extraarg); +int so_file_readc(unsigned char *, STORE_S *); +int so_file_readc_locale(unsigned char *, STORE_S *); +int so_file_readc_getchar(unsigned char *c, void *extraarg); +int so_cs_puts(STORE_S *, char *); +int so_cs_puts_locale(STORE_S *, char *); +int so_file_puts(STORE_S *, char *); +int so_file_puts_locale(STORE_S *, char *); +int so_reaquire(STORE_S *); +#ifdef _WINDOWS +int so_file_readc_windows(unsigned char *, STORE_S *); +#endif /* _WINDOWS */ +#ifdef SMIME +int so_bio_writec(int, STORE_S *); +int so_bio_readc(unsigned char *, STORE_S *); +int so_bio_puts(STORE_S *, char *); +#endif /* SMIME */ + + +/* + * place holders for externally defined storage object driver + */ +static struct externalstoreobjectdata { + STORE_S *(*get)(void); + int (*give)(STORE_S **); + int (*writec)(int, STORE_S *); + int (*readc)(unsigned char *, STORE_S *); + int (*puts)(STORE_S *, char *); + int (*seek)(STORE_S *, long, int); + int (*truncate)(STORE_S *, off_t); + int (*tell)(STORE_S *); +} etsod; + + +#define MSIZE_INIT 8192 +#define MSIZE_INC 4096 + + +#ifdef S_IREAD +#define OP_MD_USER (S_IREAD | S_IWRITE) +#else +#define OP_MD_USER 0600 +#endif + +#ifdef S_IRUSR +#define OP_MD_ALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | \ + S_IROTH | S_IWOTH) +#else +#define OP_MD_ALL 0666 +#endif + + +/* + * allocate resources associated with the specified type of + * storage. If requesting a named file object, open it for + * appending, else just open a temp file. + * + * return the filled in storage object + */ +STORE_S * +so_get(SourceType source, char *name, int rtype) + /* requested storage type */ + /* file name */ + /* file access type */ +{ + STORE_S *so = (STORE_S *)fs_get(sizeof(STORE_S)); + + memset(so, 0, sizeof(STORE_S)); + so->flags |= rtype; + + so->cb.cbuf[0] = '\0'; + so->cb.cbufp = so->cb.cbuf; + so->cb.cbufend = so->cb.cbuf; + + if(name) /* stash the name */ + so->name = cpystr(name); +#ifdef DOS + else if(source == TmpFileStar || source == FileStar){ + /* + * Coerce to TmpFileStar. The MSC library's "tmpfile()" + * doesn't observe the "TMP" or "TEMP" environment vars and + * always wants to write "\". This is problematic in shared, + * networked environments. + */ + source = TmpFileStar; + so->name = temp_nam(NULL, "pi"); + } +#else + else if(source == TmpFileStar) /* make one up! */ + so->name = temp_nam(NULL, "pine-tmp"); +#endif + + so->src = source; + if(so->src == FileStar || so->src == TmpFileStar){ +#ifdef _WINDOWS + so->writec = so_file_writec; + so->readc = (rtype & READ_FROM_LOCALE) ? so_file_readc_windows + : so_file_readc; +#else /* UNIX */ + so->writec = (rtype & WRITE_TO_LOCALE) ? so_file_writec_locale + : so_file_writec; + so->readc = (rtype & READ_FROM_LOCALE) ? so_file_readc_locale + : so_file_readc; +#endif /* UNIX */ + so->puts = (rtype & WRITE_TO_LOCALE) ? so_file_puts_locale + : so_file_puts; + + /* + * The reason for both FileStar and TmpFileStar types is + * that, named or unnamed, TmpFileStar's are unlinked + * when the object is given back to the system. This is + * useful for keeping us from running out of file pointers as + * the pointer associated with the object can be temporarily + * returned to the system without destroying the object. + * + * The programmer is warned to be careful not to assign the + * TmpFileStar type to any files that are expected to remain + * after the dust has settled! + */ + if(so->name){ + if(!(so->txt = so_file_open(so))){ + dprint((1, "so_get error: %s : %s", + so->name ? so->name : "?", + error_description(errno))); + if(source == TmpFileStar) + our_unlink(so->name); + + fs_give((void **)&so->name); + fs_give((void **)&so); /* so freed & set to NULL */ + } + } + else{ + if(!(so->txt = (void *) create_tmpfile())){ + dprint((1, "so_get error: tmpfile : %s", + error_description(errno))); + fs_give((void **)&so); /* so freed & set to NULL */ + } + } + } + else if(so->src == ExternalText && etsod.get){ + so->writec = etsod.writec; + so->readc = etsod.readc; + so->puts = etsod.puts; + if(!(so->txt = (*etsod.get)())){ + dprint((1, "so_get error: external driver allocation error")); + + if(so->name) + fs_give((void **)&so->name); + + fs_give((void **)&so); /* so freed & set to NULL */ + } + } +#ifdef SMIME + else if(so->src == BioType){ + so->writec = so_bio_writec; + so->readc = so_bio_readc; + so->puts = so_bio_puts; + + if(!(so->txt = BIO_new(BIO_s_mem()))){ + dprint((1, "so_get error: BIO driver allocation error")); + + if(so->name) + fs_give((void **) &so->name); + + fs_give((void **) &so); /* so freed & set to NULL */ + } + } +#endif /* SMIME */ + else{ + so->writec = (rtype & WRITE_TO_LOCALE) ? so_cs_writec_locale + : so_cs_writec; + so->readc = (rtype & READ_FROM_LOCALE) ? so_cs_readc_locale + : so_cs_readc; + so->puts = (rtype & WRITE_TO_LOCALE) ? so_cs_puts_locale + : so_cs_puts; + + so->txt = (void *)fs_get((size_t) MSIZE_INIT * sizeof(char)); + so->dp = so->eod = (unsigned char *) so->txt; + so->eot = so->dp + MSIZE_INIT; + memset(so->eod, 0, so->eot - so->eod); + } + + return(so); +} + + +/* + * so_give - free resources associated with a storage object and then + * the object itself. + */ +int +so_give(STORE_S **so) +{ + int ret = 0; + + if(!(so && (*so))) + return(ret); + + if((*so)->src == FileStar || (*so)->src == TmpFileStar){ + if((*so)->txt) /* disassociate from storage */ + ret = fclose((FILE *)(*so)->txt) == EOF ? -1 : 0; + + if((*so)->name && (*so)->src == TmpFileStar) + our_unlink((*so)->name); /* really disassociate! */ + } + else if((*so)->txt && (*so)->src == ExternalText){ + if(etsod.give) + (*etsod.give)((*so)->txt); + } +#ifdef SMIME + else if((*so)->txt && (*so)->src == BioType){ + BIO *b = (BIO *) (*so)->txt; + + BIO_free(b); + } +#endif /* SMIME */ + else if((*so)->txt) + fs_give((void **)&((*so)->txt)); + + if((*so)->name) + fs_give((void **)&((*so)->name)); /* blast the name */ + + /* release attribute list */ + mail_free_body_parameter(&(*so)->attr); + + fs_give((void **)so); /* release the object */ + + return(ret); +} + + +/* + * so_register_external_driver - hokey way to get pico-dependent storage object + * support out of pith library + */ +void +so_register_external_driver(STORE_S *(*get)(void), + int (*give)(STORE_S **), + int (*writec)(int, STORE_S *), + int (*readc)(unsigned char *, STORE_S *), + int (*puts)(STORE_S *, char *), + int (*seek)(STORE_S *, long int, int), + int (*truncate)(STORE_S *, off_t), + int (*tell)(STORE_S *)) +{ + memset(&etsod, 0, sizeof(etsod)); + if(get) + etsod.get = get; + + if(give) + etsod.give = give; + + if(writec) + etsod.writec = writec; + + if(readc) + etsod.readc = readc; + + if(puts) + etsod.puts = puts; + + if(seek) + etsod.seek = seek; + + if(truncate) + etsod.truncate = truncate; + + if(tell) + etsod.tell = tell; +} + + +void * +so_file_open(STORE_S *so) +{ + char *type = ((so->flags) & WRITE_ACCESS) ? "a+" : "r"; + int flags, fd, + mode = (((so->flags) & OWNER_ONLY) || so->src == TmpFileStar) + ? OP_MD_USER : OP_MD_ALL; + + /* + * Careful. EDIT_ACCESS and WRITE_TO_LOCALE/READ_FROM_LOCALE will + * not work together. + */ + if(so->flags & WRITE_ACCESS){ + flags = O_RDWR | O_CREAT | O_APPEND | O_BINARY; + } + else{ + flags = O_RDONLY; + if(so->flags & READ_FROM_LOCALE){ + flags |= _O_WTEXT; + } + else{ + flags |= O_BINARY; + } + } + + /* + * Use open instead of fopen so we can make temp files private. + * I believe the "b" or "t" in the type isn't necessary in the fdopen call + * because we already set O_BINARY or _O_U8TEXT or _O_WTEXT in the open. + */ + return(((fd = our_open(so->name, flags, mode)) > -1) + ? (so->txt = (void *) fdopen(fd, type)) : NULL); +} + + +/* + * put a character into the specified storage object, + * expanding if neccessary + * + * return 1 on success and 0 on failure + */ +int +so_cs_writec(int c, STORE_S *so) +{ + if(so->dp >= so->eot){ + size_t incr; + size_t cur_o = so->dp - (unsigned char *) so->txt; + size_t data_o = so->eod - (unsigned char *) so->txt; + size_t size = (so->eot - (unsigned char *) so->txt); + + /* + * We estimate the size we're going to need at the beginning + * so it shouldn't normally happen that we run out of space and + * come here. If we do come here, it is probably because there + * are lots of handles in the message or lots of quote coloring. + * In either case, the overhead of those is high so we don't want + * to keep adding little bits and resizing. Add 50% each time + * instead. + */ + incr = MAX(size/2, MSIZE_INC); + size += incr; + + fs_resize(&so->txt, size * sizeof(char)); + so->dp = (unsigned char *) so->txt + cur_o; + so->eod = (unsigned char *) so->txt + data_o; + so->eot = (unsigned char *) so->txt + size; + memset(so->eod, 0, so->eot - so->eod); + } + + *so->dp++ = (unsigned char) c; + if(so->dp > so->eod) + so->eod = so->dp; + + return(1); +} + + +/* + * The locale version converts from UTF-8 to user's locale charset + * before writing the characters. + */ +int +so_cs_writec_locale(int c, STORE_S *so) +{ + int rv = 1; + int i, outchars; + unsigned char obuf[MAX(MB_LEN_MAX,32)]; + + if((outchars = utf8_to_locale(c, &so->cb, obuf, sizeof(obuf))) != 0){ + for(i = 0; i < outchars; i++) + if(so_cs_writec(obuf[i], so) != 1){ + rv = 0; + break; + } + } + + return(rv); +} + + +int +so_file_writec(int c, STORE_S *so) +{ + unsigned char ch = (unsigned char) c; + int rv = 0; + + if(so->txt || so_reaquire(so)) + do + rv = fwrite(&ch,sizeof(unsigned char),(size_t)1,(FILE *)so->txt); + while(!rv && ferror((FILE *)so->txt) && errno == EINTR); + + return(rv); +} + + +/* + * The locale version converts from UTF-8 to user's locale charset + * before writing the characters. + */ +int +so_file_writec_locale(int c, STORE_S *so) +{ + int rv = 1; + int i, outchars; + unsigned char obuf[MAX(MB_LEN_MAX,32)]; + + if((outchars = utf8_to_locale(c, &so->cb, obuf, sizeof(obuf))) != 0){ + for(i = 0; i < outchars; i++) + if(so_file_writec(obuf[i], so) != 1){ + rv = 0; + break; + } + } + + return(rv); +} + + +/* + * get a character from the specified storage object. + * + * return 1 on success and 0 on failure + */ +int +so_cs_readc(unsigned char *c, STORE_S *so) +{ + return((so->dp < so->eod) ? *c = *(so->dp)++, 1 : 0); +} + + +/* + * The locale version converts from user's locale charset to UTF-8 + * after reading the characters and before returning to the caller. + */ +int +so_cs_readc_locale(unsigned char *c, STORE_S *so) +{ + return(generic_readc_locale(c, so_cs_readc_getchar, so, &so->cb)); +} + + +int +so_cs_readc_getchar(unsigned char *c, void *extraarg) +{ + STORE_S *so; + + so = (STORE_S *) extraarg; + return(so_cs_readc(c, so)); +} + + +int +so_file_readc(unsigned char *c, STORE_S *so) +{ + int rv = 0; + + if(so->txt || so_reaquire(so)) + do + rv = fread(c, sizeof(char), (size_t)1, (FILE *)so->txt); + while(!rv && ferror((FILE *)so->txt) && errno == EINTR); + + return(rv); +} + + +/* + * The locale version converts from user's locale charset to UTF-8 + * after reading the characters and before returning to the caller. + */ +int +so_file_readc_locale(unsigned char *c, STORE_S *so) +{ + return(generic_readc_locale(c, so_file_readc_getchar, so, &so->cb)); +} + + +int +so_file_readc_getchar(unsigned char *c, void *extraarg) +{ + STORE_S *so; + + so = (STORE_S *) extraarg; + return(so_file_readc(c, so)); +} + + +#ifdef _WINDOWS +/* + * Read unicode characters from windows filesystem and return + * them as a stream of UTF-8 characters. The stream is assumed + * opened so that it will know how to put together the unicode. + */ +int +so_file_readc_windows(unsigned char *c, STORE_S *so) +{ + int rv = 0; + UCS ucs; + + /* already got some from previous call? */ + if(so->cb.cbufend > so->cb.cbuf){ + *c = *so->cb.cbufp; + so->cb.cbufp++; + rv++; + if(so->cb.cbufp >= so->cb.cbufend){ + so->cb.cbufend = so->cb.cbuf; + so->cb.cbufp = so->cb.cbuf; + } + + return(rv); + } + + if(so->txt || so_reaquire(so)){ + /* windows only so second arg is ignored */ + ucs = read_a_wide_char((FILE *) so->txt, NULL); + rv = (ucs == CCONV_EOF) ? 0 : 1; + } + + if(rv){ + /* + * Now we need to convert the UCS character to UTF-8 + * and dole out the UTF-8 one char at a time. + */ + so->cb.cbufend = utf8_put(so->cb.cbuf, (unsigned long) ucs); + so->cb.cbufp = so->cb.cbuf; + if(so->cb.cbufend > so->cb.cbuf){ + *c = *so->cb.cbufp; + so->cb.cbufp++; + if(so->cb.cbufp >= so->cb.cbufend){ + so->cb.cbufend = so->cb.cbuf; + so->cb.cbufp = so->cb.cbuf; + } + } + else + *c = '?'; + } + + return(rv); +} +#endif /* _WINDOWS */ + + +/* + * write a string into the specified storage object, + * expanding if necessary (and cheating if the object + * happens to be a file!) + * + * return 1 on success and 0 on failure + */ +int +so_cs_puts(STORE_S *so, char *s) +{ + int slen = strlen(s); + + if(so->dp + slen >= so->eot){ + register size_t cur_o = so->dp - (unsigned char *) so->txt; + register size_t data_o = so->eod - (unsigned char *) so->txt; + register size_t len = so->eot - (unsigned char *) so->txt; + while(len <= cur_o + slen + 1){ + size_t incr; + + incr = MAX(len/2, MSIZE_INC); + len += incr; + } + + fs_resize(&so->txt, len * sizeof(char)); + so->dp = (unsigned char *)so->txt + cur_o; + so->eod = (unsigned char *)so->txt + data_o; + so->eot = (unsigned char *)so->txt + len; + memset(so->eod, 0, so->eot - so->eod); + } + + memcpy(so->dp, s, slen); + so->dp += slen; + if(so->dp > so->eod) + so->eod = so->dp; + + return(1); +} + + +int +so_cs_puts_locale(STORE_S *so, char *s) +{ + int slen = strlen(s); + + while(slen--) + if(!so_cs_writec_locale((unsigned char) *s++, so)) + return(0); + + return(1); +} + + +int +so_file_puts(STORE_S *so, char *s) +{ + int rv = *s ? 0 : 1; + + if(!rv && (so->txt || so_reaquire(so))) + do + rv = fwrite(s, strlen(s)*sizeof(char), (size_t)1, (FILE *)so->txt); + while(!rv && ferror((FILE *)so->txt) && errno == EINTR); + + return(rv); +} + + +int +so_file_puts_locale(STORE_S *so, char *s) +{ + int slen = strlen(s); + + while(slen--) + if(!so_file_writec_locale((unsigned char) *s++, so)) + return(0); + + return(1); +} + + +#ifdef SMIME +/* + * put a character into the specified storage object, + * expanding if neccessary + * + * return 1 on success and 0 on failure + */ +int +so_bio_writec(int c, STORE_S *so) +{ + if(so->txt && so->src == BioType){ + unsigned char ch[1]; + BIO *b = (BIO *) so->txt; + + ch[0] = (unsigned char) (c & 0xff); + + if(BIO_write(b, ch, 1) >= 1) + return(1); + } + + return(0); +} + + +int +so_bio_readc(unsigned char *c, STORE_S *so) +{ + if(so->txt && so->src == BioType){ + unsigned char ch[1]; + BIO *b = (BIO *) so->txt; + + if(BIO_read(b, ch, 1) >= 1){ + *c = ch[0]; + return(1); + } + } + + return(0); +} + + +/* + * write a string into the specified storage object, + * expanding if necessary (and cheating if the object + * happens to be a file!) + * + * return 1 on success and 0 on failure + */ +int +so_bio_puts(STORE_S *so, char *s) +{ + + if(so->txt && so->src == BioType){ + BIO *b = (BIO *) so->txt; + int slen = strlen(s); + + if(BIO_puts(b, s) >= slen) + return(1); + } + + return(1); +} +#endif /* SMIME */ + + +/* + * + */ +int +so_nputs(STORE_S *so, char *s, long int n) +{ + while(n--) + if(!so_writec((unsigned char) *s++, so)) + return(0); /* ERROR putting char ! */ + + return(1); +} + + +/* + * Position the storage object's pointer to the given offset + * from the start of the object's data. + */ +int +so_seek(STORE_S *so, long int pos, int orig) +{ + if(so->src == CharStar){ + switch(orig){ + case 0 : /* SEEK_SET */ + return((pos < so->eod - (unsigned char *) so->txt) + ? so->dp = (unsigned char *)so->txt + pos, 0 : -1); + case 1 : /* SEEK_CUR */ + return((pos > 0) + ? ((pos < so->eod - so->dp) ? so->dp += pos, 0: -1) + : ((pos < 0) + ? ((-pos < so->dp - (unsigned char *)so->txt) + ? so->dp += pos, 0 : -1) + : 0)); + case 2 : /* SEEK_END */ + return((pos > 0) + ? -1 + : ((-pos <= so->eod - (unsigned char *) so->txt) + ? so->dp = so->eod + pos, 0 : -1)); + default : + return(-1); + } + } + else if(so->src == ExternalText){ + if(etsod.seek) + return((*etsod.seek)(so->txt, pos, orig)); + + fatal("programmer botch: unsupported so_seek call"); + /*NOTREACHED*/ + return(0); /* suppress dumb compiler warnings */ + } +#ifdef SMIME + else if(so->src == BioType){ + BIO *b = (BIO *) so->txt; + + if(b && BIO_method_type(b) != BIO_TYPE_MEM) + (void) BIO_reset(b); + + return(0); + } +#endif /* SMIME */ + else /* FileStar or TmpFileStar */ + return((so->txt || so_reaquire(so)) + ? fseek((FILE *)so->txt,pos,orig) + : -1); +} + + +/* + * Change the given storage object's size to that specified. If size + * is less than the current size, the internal pointer is adjusted and + * all previous data beyond the given size is lost. + * + * Returns 0 on failure. + */ +int +so_truncate(STORE_S *so, long int size) +{ + if(so->src == CharStar){ + if(so->eod < (unsigned char *) so->txt + size){ /* alloc! */ + unsigned char *newtxt = (unsigned char *) so->txt; + register size_t len = so->eot - (unsigned char *) so->txt; + + while(len <= size) + len += MSIZE_INC; /* need to resize! */ + + if(len > so->eot - (unsigned char *) newtxt){ + fs_resize((void **) &newtxt, len * sizeof(char)); + so->eot = newtxt + len; + so->eod = newtxt + (so->eod - (unsigned char *) so->txt); + memset(so->eod, 0, so->eot - so->eod); + } + + so->eod = newtxt + size; + so->dp = newtxt + (so->dp - (unsigned char *) so->txt); + so->txt = newtxt; + } + else if(so->eod > (unsigned char *) so->txt + size){ + if(so->dp > (so->eod = (unsigned char *)so->txt + size)) + so->dp = so->eod; + + memset(so->eod, 0, so->eot - so->eod); + } + + return(1); + } + else if(so->src == ExternalText){ + if(etsod.truncate) + return((*etsod.truncate)(so, (off_t) size)); + + fatal("programmer botch: unsupported so_truncate call"); + /*NOTREACHED*/ + return(0); /* suppress dumb compiler warnings */ + } +#ifdef SMIME + else if(so->src == BioType){ + fatal("programmer botch: unsupported so_truncate call for BioType"); + /*NOTREACHED*/ + return(0); /* suppress dumb compiler warnings */ + +#ifdef notdef + long len; + BIO *b = (BIO *) so->txt; + + if(b){ + BUF_MEM *biobuf = NULL; + + BIO_get_mem_ptr(b, &biobuf); + if(biobuf){ + BUF_MEM_grow(biobuf, size); + return(1); + } + } + + return(0); +#endif /* notdef */ + } +#endif /* SMIME */ + else /* FileStar or TmpFileStar */ + return(fflush((FILE *) so->txt) != EOF + && fseek((FILE *) so->txt, size, 0) == 0 + && ftruncate(fileno((FILE *)so->txt), (off_t) size) == 0); +} + + +/* + * Report given storage object's position indicator. + * Returns 0 on failure. + */ +long +so_tell(STORE_S *so) +{ + if(so->src == CharStar){ + return((long) (so->dp - (unsigned char *) so->txt)); + } + else if(so->src == ExternalText){ + if(etsod.tell) + return((*etsod.tell)(so)); + + fatal("programmer botch: unsupported so_tell call"); + /*NOTREACHED*/ + return(0); /* suppress dumb compiler warnings */ + } +#ifdef SMIME + else if(so->src == BioType){ + fatal("programmer botch: unsupported so_tell call for BioType"); + /*NOTREACHED*/ + return(0); /* suppress dumb compiler warnings */ + } +#endif /* SMIME */ + else /* FileStar or TmpFileStar */ + return(ftell((FILE *) so->txt)); +} + + +/* + * so_attr - hook to hang random attributes onto the storage object + */ +char * +so_attr(STORE_S *so, char *key, char *value) +{ + if(so && key){ + if(value){ + PARAMETER **pp = &so->attr; + + while(1){ + if(*pp){ + if((*pp)->attribute && !strcmp(key, (*pp)->attribute)){ + if((*pp)->value) + fs_give((void **)&(*pp)->value); + + break; + } + + pp = &(*pp)->next; + } + else{ + *pp = mail_newbody_parameter(); + (*pp)->attribute = cpystr(key); + break; + } + } + + return((*pp)->value = cpystr(value)); + } + else{ + PARAMETER *p; + + for(p = so->attr; p; p = p->next) + if(p->attribute && !strcmp(key, p->attribute)) + return(p->value); + } + } + + return(NULL); +} + + +/* + * so_release - a rather misnamed function. the idea is to release + * what system resources we can (e.g., open files). + * while maintaining a reference to it. + * it's up to the functions that deal with this object + * next to re-aquire those resources. + */ +int +so_release(STORE_S *so) +{ + if(so->txt && so->name && (so->src == FileStar || so->src == TmpFileStar)){ + if(fget_pos((FILE *)so->txt, (fpos_t *)&(so->used)) == 0){ + fclose((FILE *)so->txt); /* free the handle! */ + so->txt = NULL; + } + } + + return(1); +} + + +/* + * so_reaquire - get any previously released system resources we + * may need for the given storage object. + * NOTE: at the moment, only FILE * types of objects are + * effected, so it only needs to be called before + * references to them. + * + */ +int +so_reaquire(STORE_S *so) +{ + int rv = 1; + + if(!so->txt && (so->src == FileStar || so->src == TmpFileStar)){ + if(!(so->txt = so_file_open(so))){ + q_status_message2(SM_ORDER,3,5, "ERROR reopening %.200s : %.200s", + so->name, error_description(errno)); + rv = 0; + } + else if(fset_pos((FILE *)so->txt, (fpos_t *)&(so->used))){ + q_status_message2(SM_ORDER, 3, 5, + "ERROR positioning in %.200s : %.200s", + so->name, error_description(errno)); + rv = 0; + } + } + + return(rv); +} + + +/* + * so_text - return a pointer to the text the store object passed + */ +void * +so_text(STORE_S *so) +{ + return((so) ? so->txt : NULL); +} + + +/* + * Similar to fgets but reading from a storage object. + */ +char * +so_fgets(STORE_S *so, char *s, size_t size) +{ + unsigned char c; + char *p = s; + + while(--size > 0 && so_readc(&c, so) > 0){ + *p++ = (char) c; + if(c == '\n') + break; + } + + *p = '\0'; + + return((p>s) ? s : NULL); +} |