* New version 2.21
[alpine.git] / pith / store.c
blob84f03f1a632d70dab57efc501cd87beaeec603f1
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: store.c 1074 2008-06-04 00:08:43Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2013-2017 Eduardo Chappa
8 * Copyright 2006-2008 University of Washington
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
20 * GENERALIZED STORAGE FUNCTIONS. Idea is to allow creation of
21 * storage objects that can be written into and read from without
22 * the caller knowing if the storage is core or in a file
23 * or whatever.
27 #include "../pith/headers.h"
28 #include "../pith/store.h"
29 #include "../pith/status.h"
30 #include "../pith/state.h"
31 #include "../pico/keydefs.h"
32 #ifdef SMIME
33 #include <openssl/buffer.h>
34 #endif /* SMIME */
38 * Internal prototypes
40 void *so_file_open(STORE_S *);
41 int so_cs_writec(int, STORE_S *);
42 int so_cs_writec_locale(int, STORE_S *);
43 int so_file_writec(int, STORE_S *);
44 int so_file_writec_locale(int, STORE_S *);
45 int so_cs_readc(unsigned char *, STORE_S *);
46 int so_cs_readc_locale(unsigned char *, STORE_S *);
47 int so_cs_readc_getchar(unsigned char *c, void *extraarg);
48 int so_file_readc(unsigned char *, STORE_S *);
49 int so_file_readc_locale(unsigned char *, STORE_S *);
50 int so_file_readc_getchar(unsigned char *c, void *extraarg);
51 int so_cs_puts(STORE_S *, char *);
52 int so_cs_puts_locale(STORE_S *, char *);
53 int so_file_puts(STORE_S *, char *);
54 int so_file_puts_locale(STORE_S *, char *);
55 int so_reaquire(STORE_S *);
56 #ifdef _WINDOWS
57 int so_file_readc_windows(unsigned char *, STORE_S *);
58 #endif /* _WINDOWS */
59 #ifdef SMIME
60 int so_bio_writec(int, STORE_S *);
61 int so_bio_readc(unsigned char *, STORE_S *);
62 int so_bio_puts(STORE_S *, char *);
63 #endif /* SMIME */
67 * place holders for externally defined storage object driver
69 static struct externalstoreobjectdata {
70 STORE_S *(*get)(void);
71 int (*give)(STORE_S **);
72 int (*writec)(int, STORE_S *);
73 int (*readc)(unsigned char *, STORE_S *);
74 int (*puts)(STORE_S *, char *);
75 int (*seek)(STORE_S *, long, int);
76 int (*truncate)(STORE_S *, off_t);
77 int (*tell)(STORE_S *);
78 } etsod;
81 #define MSIZE_INIT 8192
82 #define MSIZE_INC 4096
85 #ifdef S_IREAD
86 #define OP_MD_USER (S_IREAD | S_IWRITE)
87 #else
88 #define OP_MD_USER 0600
89 #endif
91 #ifdef S_IRUSR
92 #define OP_MD_ALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | \
93 S_IROTH | S_IWOTH)
94 #else
95 #define OP_MD_ALL 0666
96 #endif
100 * allocate resources associated with the specified type of
101 * storage. If requesting a named file object, open it for
102 * appending, else just open a temp file.
104 * return the filled in storage object
106 STORE_S *
107 so_get(SourceType source, char *name, int rtype)
108 /* requested storage type */
109 /* file name */
110 /* file access type */
112 STORE_S *so = (STORE_S *)fs_get(sizeof(STORE_S));
114 memset(so, 0, sizeof(STORE_S));
115 so->flags |= rtype;
117 so->cb.cbuf[0] = '\0';
118 so->cb.cbufp = so->cb.cbuf;
119 so->cb.cbufend = so->cb.cbuf;
121 if(name) /* stash the name */
122 so->name = cpystr(name);
123 #ifdef DOS
124 else if(source == TmpFileStar || source == FileStar){
126 * Coerce to TmpFileStar. The MSC library's "tmpfile()"
127 * doesn't observe the "TMP" or "TEMP" environment vars and
128 * always wants to write "\". This is problematic in shared,
129 * networked environments.
131 source = TmpFileStar;
132 so->name = temp_nam(NULL, "pi");
134 #else
135 else if(source == TmpFileStar) /* make one up! */
136 so->name = temp_nam(NULL, "pine-tmp");
137 #endif
139 so->src = source;
140 if(so->src == FileStar || so->src == TmpFileStar){
141 #ifdef _WINDOWS
142 so->writec = so_file_writec;
143 so->readc = (rtype & READ_FROM_LOCALE) ? so_file_readc_windows
144 : so_file_readc;
145 #else /* UNIX */
146 so->writec = (rtype & WRITE_TO_LOCALE) ? so_file_writec_locale
147 : so_file_writec;
148 so->readc = (rtype & READ_FROM_LOCALE) ? so_file_readc_locale
149 : so_file_readc;
150 #endif /* UNIX */
151 so->puts = (rtype & WRITE_TO_LOCALE) ? so_file_puts_locale
152 : so_file_puts;
155 * The reason for both FileStar and TmpFileStar types is
156 * that, named or unnamed, TmpFileStar's are unlinked
157 * when the object is given back to the system. This is
158 * useful for keeping us from running out of file pointers as
159 * the pointer associated with the object can be temporarily
160 * returned to the system without destroying the object.
162 * The programmer is warned to be careful not to assign the
163 * TmpFileStar type to any files that are expected to remain
164 * after the dust has settled!
166 if(so->name){
167 if(!(so->txt = so_file_open(so))){
168 dprint((1, "so_get error: %s : %s",
169 so->name ? so->name : "?",
170 error_description(errno)));
171 if(source == TmpFileStar)
172 our_unlink(so->name);
174 fs_give((void **)&so->name);
175 fs_give((void **)&so); /* so freed & set to NULL */
178 else{
179 if(!(so->txt = (void *) create_tmpfile())){
180 dprint((1, "so_get error: tmpfile : %s",
181 error_description(errno)));
182 fs_give((void **)&so); /* so freed & set to NULL */
186 else if(so->src == ExternalText && etsod.get){
187 so->writec = etsod.writec;
188 so->readc = etsod.readc;
189 so->puts = etsod.puts;
190 if(!(so->txt = (*etsod.get)())){
191 dprint((1, "so_get error: external driver allocation error"));
193 if(so->name)
194 fs_give((void **)&so->name);
196 fs_give((void **)&so); /* so freed & set to NULL */
199 #ifdef SMIME
200 else if(so->src == BioType){
201 so->writec = so_bio_writec;
202 so->readc = so_bio_readc;
203 so->puts = so_bio_puts;
205 if(!(so->txt = BIO_new(BIO_s_mem()))){
206 dprint((1, "so_get error: BIO driver allocation error"));
208 if(so->name)
209 fs_give((void **) &so->name);
211 fs_give((void **) &so); /* so freed & set to NULL */
214 #endif /* SMIME */
215 else{
216 so->writec = (rtype & WRITE_TO_LOCALE) ? so_cs_writec_locale
217 : so_cs_writec;
218 so->readc = (rtype & READ_FROM_LOCALE) ? so_cs_readc_locale
219 : so_cs_readc;
220 so->puts = (rtype & WRITE_TO_LOCALE) ? so_cs_puts_locale
221 : so_cs_puts;
223 so->txt = (void *)fs_get((size_t) MSIZE_INIT * sizeof(char));
224 so->dp = so->eod = (unsigned char *) so->txt;
225 so->eot = so->dp + MSIZE_INIT;
226 memset(so->eod, 0, so->eot - so->eod);
229 return(so);
234 * so_give - free resources associated with a storage object and then
235 * the object itself.
238 so_give(STORE_S **so)
240 int ret = 0;
242 if(!(so && (*so)))
243 return(ret);
245 if((*so)->src == FileStar || (*so)->src == TmpFileStar){
246 if((*so)->txt) /* disassociate from storage */
247 ret = fclose((FILE *)(*so)->txt) == EOF ? -1 : 0;
249 if((*so)->name && (*so)->src == TmpFileStar)
250 our_unlink((*so)->name); /* really disassociate! */
252 else if((*so)->txt && (*so)->src == ExternalText){
253 if(etsod.give)
254 (*etsod.give)((*so)->txt);
256 #ifdef SMIME
257 else if((*so)->txt && (*so)->src == BioType){
258 BIO *b = (BIO *) (*so)->txt;
260 BIO_free(b);
262 #endif /* SMIME */
263 else if((*so)->txt)
264 fs_give((void **)&((*so)->txt));
266 if((*so)->name)
267 fs_give((void **)&((*so)->name)); /* blast the name */
269 /* release attribute list */
270 mail_free_body_parameter(&(*so)->attr);
272 fs_give((void **)so); /* release the object */
274 return(ret);
279 * so_register_external_driver - hokey way to get pico-dependent storage object
280 * support out of pith library
282 void
283 so_register_external_driver(STORE_S *(*get)(void),
284 int (*give)(STORE_S **),
285 int (*writec)(int, STORE_S *),
286 int (*readc)(unsigned char *, STORE_S *),
287 int (*puts)(STORE_S *, char *),
288 int (*seek)(STORE_S *, long int, int),
289 int (*truncate)(STORE_S *, off_t),
290 int (*tell)(STORE_S *))
292 memset(&etsod, 0, sizeof(etsod));
293 if(get)
294 etsod.get = get;
296 if(give)
297 etsod.give = give;
299 if(writec)
300 etsod.writec = writec;
302 if(readc)
303 etsod.readc = readc;
305 if(puts)
306 etsod.puts = puts;
308 if(seek)
309 etsod.seek = seek;
311 if(truncate)
312 etsod.truncate = truncate;
314 if(tell)
315 etsod.tell = tell;
319 void *
320 so_file_open(STORE_S *so)
322 char *type = ((so->flags) & WRITE_ACCESS) ? "a+" : "r";
323 int flags, fd,
324 mode = (((so->flags) & OWNER_ONLY) || so->src == TmpFileStar)
325 ? OP_MD_USER : OP_MD_ALL;
328 * Careful. EDIT_ACCESS and WRITE_TO_LOCALE/READ_FROM_LOCALE will
329 * not work together.
331 if(so->flags & WRITE_ACCESS){
332 flags = O_RDWR | O_CREAT | O_APPEND | O_BINARY;
334 else{
335 flags = O_RDONLY;
336 if(so->flags & READ_FROM_LOCALE){
337 flags |= _O_WTEXT;
339 else{
340 flags |= O_BINARY;
345 * Use open instead of fopen so we can make temp files private.
346 * I believe the "b" or "t" in the type isn't necessary in the fdopen call
347 * because we already set O_BINARY or _O_U8TEXT or _O_WTEXT in the open.
349 return(((fd = our_open(so->name, flags, mode)) > -1)
350 ? (so->txt = (void *) fdopen(fd, type)) : NULL);
355 * put a character into the specified storage object,
356 * expanding if neccessary
358 * return 1 on success and 0 on failure
361 so_cs_writec(int c, STORE_S *so)
363 if(so->dp >= so->eot){
364 size_t incr;
365 size_t cur_o = so->dp - (unsigned char *) so->txt;
366 size_t data_o = so->eod - (unsigned char *) so->txt;
367 size_t size = (so->eot - (unsigned char *) so->txt);
370 * We estimate the size we're going to need at the beginning
371 * so it shouldn't normally happen that we run out of space and
372 * come here. If we do come here, it is probably because there
373 * are lots of handles in the message or lots of quote coloring.
374 * In either case, the overhead of those is high so we don't want
375 * to keep adding little bits and resizing. Add 50% each time
376 * instead.
378 incr = MAX(size/2, MSIZE_INC);
379 size += incr;
381 fs_resize(&so->txt, size * sizeof(char));
382 so->dp = (unsigned char *) so->txt + cur_o;
383 so->eod = (unsigned char *) so->txt + data_o;
384 so->eot = (unsigned char *) so->txt + size;
385 memset(so->eod, 0, so->eot - so->eod);
388 *so->dp++ = (unsigned char) c;
389 if(so->dp > so->eod)
390 so->eod = so->dp;
392 return(1);
397 * The locale version converts from UTF-8 to user's locale charset
398 * before writing the characters.
401 so_cs_writec_locale(int c, STORE_S *so)
403 int rv = 1;
404 int i, outchars;
405 unsigned char obuf[MAX(MB_LEN_MAX,32)];
407 if((outchars = utf8_to_locale(c, &so->cb, obuf, sizeof(obuf))) != 0){
408 for(i = 0; i < outchars; i++)
409 if(so_cs_writec(obuf[i], so) != 1){
410 rv = 0;
411 break;
415 return(rv);
420 so_file_writec(int c, STORE_S *so)
422 unsigned char ch = (unsigned char) c;
423 int rv = 0;
425 if(so->txt || so_reaquire(so))
427 rv = fwrite(&ch,sizeof(unsigned char),(size_t)1,(FILE *)so->txt);
428 while(!rv && ferror((FILE *)so->txt) && errno == EINTR);
430 return(rv);
435 * The locale version converts from UTF-8 to user's locale charset
436 * before writing the characters.
439 so_file_writec_locale(int c, STORE_S *so)
441 int rv = 1;
442 int i, outchars;
443 unsigned char obuf[MAX(MB_LEN_MAX,32)];
445 if((outchars = utf8_to_locale(c, &so->cb, obuf, sizeof(obuf))) != 0){
446 for(i = 0; i < outchars; i++)
447 if(so_file_writec(obuf[i], so) != 1){
448 rv = 0;
449 break;
453 return(rv);
458 * get a character from the specified storage object.
460 * return 1 on success and 0 on failure
463 so_cs_readc(unsigned char *c, STORE_S *so)
465 return((so->dp < so->eod) ? *c = *(so->dp)++, 1 : 0);
470 * The locale version converts from user's locale charset to UTF-8
471 * after reading the characters and before returning to the caller.
474 so_cs_readc_locale(unsigned char *c, STORE_S *so)
476 return(generic_readc_locale(c, so_cs_readc_getchar, so, &so->cb));
481 so_cs_readc_getchar(unsigned char *c, void *extraarg)
483 STORE_S *so;
485 so = (STORE_S *) extraarg;
486 return(so_cs_readc(c, so));
491 so_file_readc(unsigned char *c, STORE_S *so)
493 int rv = 0;
495 if(so->txt || so_reaquire(so))
497 rv = fread(c, sizeof(char), (size_t)1, (FILE *)so->txt);
498 while(!rv && ferror((FILE *)so->txt) && errno == EINTR);
500 return(rv);
505 * The locale version converts from user's locale charset to UTF-8
506 * after reading the characters and before returning to the caller.
509 so_file_readc_locale(unsigned char *c, STORE_S *so)
511 return(generic_readc_locale(c, so_file_readc_getchar, so, &so->cb));
516 so_file_readc_getchar(unsigned char *c, void *extraarg)
518 STORE_S *so;
520 so = (STORE_S *) extraarg;
521 return(so_file_readc(c, so));
525 #ifdef _WINDOWS
527 * Read unicode characters from windows filesystem and return
528 * them as a stream of UTF-8 characters. The stream is assumed
529 * opened so that it will know how to put together the unicode.
532 so_file_readc_windows(unsigned char *c, STORE_S *so)
534 int rv = 0;
535 UCS ucs;
537 /* already got some from previous call? */
538 if(so->cb.cbufend > so->cb.cbuf){
539 *c = *so->cb.cbufp;
540 so->cb.cbufp++;
541 rv++;
542 if(so->cb.cbufp >= so->cb.cbufend){
543 so->cb.cbufend = so->cb.cbuf;
544 so->cb.cbufp = so->cb.cbuf;
547 return(rv);
550 if(so->txt || so_reaquire(so)){
551 /* windows only so second arg is ignored */
552 ucs = read_a_wide_char((FILE *) so->txt, NULL);
553 rv = (ucs == CCONV_EOF) ? 0 : 1;
556 if(rv){
558 * Now we need to convert the UCS character to UTF-8
559 * and dole out the UTF-8 one char at a time.
561 so->cb.cbufend = utf8_put(so->cb.cbuf, (unsigned long) ucs);
562 so->cb.cbufp = so->cb.cbuf;
563 if(so->cb.cbufend > so->cb.cbuf){
564 *c = *so->cb.cbufp;
565 so->cb.cbufp++;
566 if(so->cb.cbufp >= so->cb.cbufend){
567 so->cb.cbufend = so->cb.cbuf;
568 so->cb.cbufp = so->cb.cbuf;
571 else
572 *c = '?';
575 return(rv);
577 #endif /* _WINDOWS */
581 * write a string into the specified storage object,
582 * expanding if necessary (and cheating if the object
583 * happens to be a file!)
585 * return 1 on success and 0 on failure
588 so_cs_puts(STORE_S *so, char *s)
590 int slen = strlen(s);
592 if(so->dp + slen >= so->eot){
593 register size_t cur_o = so->dp - (unsigned char *) so->txt;
594 register size_t data_o = so->eod - (unsigned char *) so->txt;
595 register size_t len = so->eot - (unsigned char *) so->txt;
596 while(len <= cur_o + slen + 1){
597 size_t incr;
599 incr = MAX(len/2, MSIZE_INC);
600 len += incr;
603 fs_resize(&so->txt, len * sizeof(char));
604 so->dp = (unsigned char *)so->txt + cur_o;
605 so->eod = (unsigned char *)so->txt + data_o;
606 so->eot = (unsigned char *)so->txt + len;
607 memset(so->eod, 0, so->eot - so->eod);
610 memcpy(so->dp, s, slen);
611 so->dp += slen;
612 if(so->dp > so->eod)
613 so->eod = so->dp;
615 return(1);
620 so_cs_puts_locale(STORE_S *so, char *s)
622 int slen = strlen(s);
624 while(slen--)
625 if(!so_cs_writec_locale((unsigned char) *s++, so))
626 return(0);
628 return(1);
633 so_file_puts(STORE_S *so, char *s)
635 int rv = *s ? 0 : 1;
637 if(!rv && (so->txt || so_reaquire(so)))
639 rv = fwrite(s, strlen(s)*sizeof(char), (size_t)1, (FILE *)so->txt);
640 while(!rv && ferror((FILE *)so->txt) && errno == EINTR);
642 return(rv);
647 so_file_puts_locale(STORE_S *so, char *s)
649 int slen = strlen(s);
651 while(slen--)
652 if(!so_file_writec_locale((unsigned char) *s++, so))
653 return(0);
655 return(1);
659 #ifdef SMIME
661 * put a character into the specified storage object,
662 * expanding if neccessary
664 * return 1 on success and 0 on failure
667 so_bio_writec(int c, STORE_S *so)
669 if(so->txt && so->src == BioType){
670 unsigned char ch[1];
671 BIO *b = (BIO *) so->txt;
673 ch[0] = (unsigned char) (c & 0xff);
675 if(BIO_write(b, ch, 1) >= 1)
676 return(1);
679 return(0);
684 so_bio_readc(unsigned char *c, STORE_S *so)
686 if(so->txt && so->src == BioType){
687 unsigned char ch[1];
688 BIO *b = (BIO *) so->txt;
690 if(BIO_read(b, ch, 1) >= 1){
691 *c = ch[0];
692 return(1);
696 return(0);
701 * write a string into the specified storage object,
702 * expanding if necessary (and cheating if the object
703 * happens to be a file!)
705 * return 1 on success and 0 on failure
708 so_bio_puts(STORE_S *so, char *s)
711 if(so->txt && so->src == BioType){
712 BIO *b = (BIO *) so->txt;
713 int slen = strlen(s);
715 if(BIO_puts(b, s) >= slen)
716 return(1);
719 return(1);
721 #endif /* SMIME */
728 so_nputs(STORE_S *so, char *s, long int n)
730 while(n--)
731 if(!so_writec((unsigned char) *s++, so))
732 return(0); /* ERROR putting char ! */
734 return(1);
739 * Position the storage object's pointer to the given offset
740 * from the start of the object's data.
743 so_seek(STORE_S *so, long int pos, int orig)
745 if(so->src == CharStar){
746 switch(orig){
747 case 0 : /* SEEK_SET */
748 return((pos < so->eod - (unsigned char *) so->txt)
749 ? so->dp = (unsigned char *)so->txt + pos, 0 : -1);
750 case 1 : /* SEEK_CUR */
751 return((pos > 0)
752 ? ((pos < so->eod - so->dp) ? so->dp += pos, 0: -1)
753 : ((pos < 0)
754 ? ((-pos < so->dp - (unsigned char *)so->txt)
755 ? so->dp += pos, 0 : -1)
756 : 0));
757 case 2 : /* SEEK_END */
758 return((pos > 0)
759 ? -1
760 : ((-pos <= so->eod - (unsigned char *) so->txt)
761 ? so->dp = so->eod + pos, 0 : -1));
762 default :
763 return(-1);
766 else if(so->src == ExternalText){
767 if(etsod.seek)
768 return((*etsod.seek)(so->txt, pos, orig));
770 fatal("programmer botch: unsupported so_seek call");
771 /*NOTREACHED*/
772 return(0); /* suppress dumb compiler warnings */
774 #ifdef SMIME
775 else if(so->src == BioType){
776 BIO *b = (BIO *) so->txt;
778 if(b && BIO_method_type(b) != BIO_TYPE_MEM)
779 (void) BIO_reset(b);
781 return(0);
783 #endif /* SMIME */
784 else /* FileStar or TmpFileStar */
785 return((so->txt || so_reaquire(so))
786 ? fseek((FILE *)so->txt,pos,orig)
787 : -1);
792 * Change the given storage object's size to that specified. If size
793 * is less than the current size, the internal pointer is adjusted and
794 * all previous data beyond the given size is lost.
796 * Returns 0 on failure.
799 so_truncate(STORE_S *so, long int size)
801 if(so->src == CharStar){
802 if(so->eod < (unsigned char *) so->txt + size){ /* alloc! */
803 unsigned char *newtxt = (unsigned char *) so->txt;
804 register size_t len = so->eot - (unsigned char *) so->txt;
806 while(len <= size)
807 len += MSIZE_INC; /* need to resize! */
809 if(len > so->eot - (unsigned char *) newtxt){
810 fs_resize((void **) &newtxt, len * sizeof(char));
811 so->eot = newtxt + len;
812 so->eod = newtxt + (so->eod - (unsigned char *) so->txt);
813 memset(so->eod, 0, so->eot - so->eod);
816 so->eod = newtxt + size;
817 so->dp = newtxt + (so->dp - (unsigned char *) so->txt);
818 so->txt = newtxt;
820 else if(so->eod > (unsigned char *) so->txt + size){
821 if(so->dp > (so->eod = (unsigned char *)so->txt + size))
822 so->dp = so->eod;
824 memset(so->eod, 0, so->eot - so->eod);
827 return(1);
829 else if(so->src == ExternalText){
830 if(etsod.truncate)
831 return((*etsod.truncate)(so, (off_t) size));
833 fatal("programmer botch: unsupported so_truncate call");
834 /*NOTREACHED*/
835 return(0); /* suppress dumb compiler warnings */
837 #ifdef SMIME
838 else if(so->src == BioType){
839 fatal("programmer botch: unsupported so_truncate call for BioType");
840 /*NOTREACHED*/
841 return(0); /* suppress dumb compiler warnings */
843 #ifdef notdef
844 long len;
845 BIO *b = (BIO *) so->txt;
847 if(b){
848 BUF_MEM *biobuf = NULL;
850 BIO_get_mem_ptr(b, &biobuf);
851 if(biobuf){
852 BUF_MEM_grow(biobuf, size);
853 return(1);
857 return(0);
858 #endif /* notdef */
860 #endif /* SMIME */
861 else /* FileStar or TmpFileStar */
862 return(fflush((FILE *) so->txt) != EOF
863 && fseek((FILE *) so->txt, size, 0) == 0
864 && ftruncate(fileno((FILE *)so->txt), (off_t) size) == 0);
869 * Report given storage object's position indicator.
870 * Returns 0 on failure.
872 long
873 so_tell(STORE_S *so)
875 if(so->src == CharStar){
876 return((long) (so->dp - (unsigned char *) so->txt));
878 else if(so->src == ExternalText){
879 if(etsod.tell)
880 return((*etsod.tell)(so));
882 fatal("programmer botch: unsupported so_tell call");
883 /*NOTREACHED*/
884 return(0); /* suppress dumb compiler warnings */
886 #ifdef SMIME
887 else if(so->src == BioType){
888 fatal("programmer botch: unsupported so_tell call for BioType");
889 /*NOTREACHED*/
890 return(0); /* suppress dumb compiler warnings */
892 #endif /* SMIME */
893 else /* FileStar or TmpFileStar */
894 return(ftell((FILE *) so->txt));
899 * so_attr - hook to hang random attributes onto the storage object
901 char *
902 so_attr(STORE_S *so, char *key, char *value)
904 if(so && key){
905 if(value){
906 PARAMETER **pp = &so->attr;
908 while(1){
909 if(*pp){
910 if((*pp)->attribute && !strcmp(key, (*pp)->attribute)){
911 if((*pp)->value)
912 fs_give((void **)&(*pp)->value);
914 break;
917 pp = &(*pp)->next;
919 else{
920 *pp = mail_newbody_parameter();
921 (*pp)->attribute = cpystr(key);
922 break;
926 return((*pp)->value = cpystr(value));
928 else{
929 PARAMETER *p;
931 for(p = so->attr; p; p = p->next)
932 if(p->attribute && !strcmp(key, p->attribute))
933 return(p->value);
937 return(NULL);
942 * so_release - a rather misnamed function. the idea is to release
943 * what system resources we can (e.g., open files).
944 * while maintaining a reference to it.
945 * it's up to the functions that deal with this object
946 * next to re-aquire those resources.
949 so_release(STORE_S *so)
951 if(so->txt && so->name && (so->src == FileStar || so->src == TmpFileStar)){
952 if(fget_pos((FILE *)so->txt, (fpos_t *)&(so->used)) == 0){
953 fclose((FILE *)so->txt); /* free the handle! */
954 so->txt = NULL;
958 return(1);
963 * so_reaquire - get any previously released system resources we
964 * may need for the given storage object.
965 * NOTE: at the moment, only FILE * types of objects are
966 * effected, so it only needs to be called before
967 * references to them.
971 so_reaquire(STORE_S *so)
973 int rv = 1;
975 if(!so->txt && (so->src == FileStar || so->src == TmpFileStar)){
976 if(!(so->txt = so_file_open(so))){
977 q_status_message2(SM_ORDER,3,5, "ERROR reopening %.200s : %.200s",
978 so->name, error_description(errno));
979 rv = 0;
981 else if(fset_pos((FILE *)so->txt, (fpos_t *)&(so->used))){
982 q_status_message2(SM_ORDER, 3, 5,
983 "ERROR positioning in %.200s : %.200s",
984 so->name, error_description(errno));
985 rv = 0;
989 return(rv);
994 * so_text - return a pointer to the text the store object passed
996 void *
997 so_text(STORE_S *so)
999 return((so) ? so->txt : NULL);
1004 * Similar to fgets but reading from a storage object.
1006 char *
1007 so_fgets(STORE_S *so, char *s, size_t size)
1009 unsigned char c;
1010 char *p = s;
1012 while(--size > 0 && so_readc(&c, so) > 0){
1013 *p++ = (char) c;
1014 if(c == '\n')
1015 break;
1018 *p = '\0';
1020 return((p>s) ? s : NULL);