Add support for tab-completion when selecting by rule
[alpine.git] / pith / store.c
bloba7ce38dc4064d696f894e20fcd359443fb5d15e0
1 /*
2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2008 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
16 * GENERALIZED STORAGE FUNCTIONS. Idea is to allow creation of
17 * storage objects that can be written into and read from without
18 * the caller knowing if the storage is core or in a file
19 * or whatever.
23 #include "../pith/headers.h"
24 #include "../pith/store.h"
25 #include "../pith/status.h"
26 #include "../pith/state.h"
27 #include "../pico/keydefs.h"
28 #ifdef SMIME
29 #include <openssl/buffer.h>
30 #endif /* SMIME */
34 * Internal prototypes
36 void *so_file_open(STORE_S *);
37 int so_cs_writec(int, STORE_S *);
38 int so_cs_writec_locale(int, STORE_S *);
39 int so_file_writec(int, STORE_S *);
40 int so_file_writec_locale(int, STORE_S *);
41 int so_cs_readc(unsigned char *, STORE_S *);
42 int so_cs_readc_locale(unsigned char *, STORE_S *);
43 int so_cs_readc_getchar(unsigned char *c, void *extraarg);
44 int so_file_readc(unsigned char *, STORE_S *);
45 int so_file_readc_locale(unsigned char *, STORE_S *);
46 int so_file_readc_getchar(unsigned char *c, void *extraarg);
47 int so_cs_puts(STORE_S *, char *);
48 int so_cs_puts_locale(STORE_S *, char *);
49 int so_file_puts(STORE_S *, char *);
50 int so_file_puts_locale(STORE_S *, char *);
51 int so_reaquire(STORE_S *);
52 #ifdef _WINDOWS
53 int so_file_readc_windows(unsigned char *, STORE_S *);
54 #endif /* _WINDOWS */
55 #ifdef SMIME
56 int so_bio_writec(int, STORE_S *);
57 int so_bio_readc(unsigned char *, STORE_S *);
58 int so_bio_puts(STORE_S *, char *);
59 #endif /* SMIME */
63 * place holders for externally defined storage object driver
65 static struct externalstoreobjectdata {
66 STORE_S *(*get)(void);
67 int (*give)(STORE_S **);
68 int (*writec)(int, STORE_S *);
69 int (*readc)(unsigned char *, STORE_S *);
70 int (*puts)(STORE_S *, char *);
71 int (*seek)(STORE_S *, long, int);
72 int (*truncate)(STORE_S *, off_t);
73 int (*tell)(STORE_S *);
74 } etsod;
77 #define MSIZE_INIT 8192
78 #define MSIZE_INC 4096
81 #ifdef S_IREAD
82 #define OP_MD_USER (S_IREAD | S_IWRITE)
83 #else
84 #define OP_MD_USER 0600
85 #endif
87 #ifdef S_IRUSR
88 #define OP_MD_ALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | \
89 S_IROTH | S_IWOTH)
90 #else
91 #define OP_MD_ALL 0666
92 #endif
96 * allocate resources associated with the specified type of
97 * storage. If requesting a named file object, open it for
98 * appending, else just open a temp file.
100 * return the filled in storage object
102 STORE_S *
103 so_get(SourceType source, char *name, int rtype)
104 /* requested storage type */
105 /* file name */
106 /* file access type */
108 STORE_S *so = (STORE_S *)fs_get(sizeof(STORE_S));
110 memset(so, 0, sizeof(STORE_S));
111 so->flags |= rtype;
113 so->cb.cbuf[0] = '\0';
114 so->cb.cbufp = so->cb.cbuf;
115 so->cb.cbufend = so->cb.cbuf;
117 if(name) /* stash the name */
118 so->name = cpystr(name);
119 #ifdef DOS
120 else if(source == TmpFileStar || source == FileStar){
122 * Coerce to TmpFileStar. The MSC library's "tmpfile()"
123 * doesn't observe the "TMP" or "TEMP" environment vars and
124 * always wants to write "\". This is problematic in shared,
125 * networked environments.
127 source = TmpFileStar;
128 so->name = temp_nam(NULL, "pi");
130 #else
131 else if(source == TmpFileStar) /* make one up! */
132 so->name = temp_nam(NULL, "pine-tmp");
133 #endif
135 so->src = source;
136 if(so->src == FileStar || so->src == TmpFileStar){
137 #ifdef _WINDOWS
138 so->writec = so_file_writec;
139 so->readc = (rtype & READ_FROM_LOCALE) ? so_file_readc_windows
140 : so_file_readc;
141 #else /* UNIX */
142 so->writec = (rtype & WRITE_TO_LOCALE) ? so_file_writec_locale
143 : so_file_writec;
144 so->readc = (rtype & READ_FROM_LOCALE) ? so_file_readc_locale
145 : so_file_readc;
146 #endif /* UNIX */
147 so->puts = (rtype & WRITE_TO_LOCALE) ? so_file_puts_locale
148 : so_file_puts;
151 * The reason for both FileStar and TmpFileStar types is
152 * that, named or unnamed, TmpFileStar's are unlinked
153 * when the object is given back to the system. This is
154 * useful for keeping us from running out of file pointers as
155 * the pointer associated with the object can be temporarily
156 * returned to the system without destroying the object.
158 * The programmer is warned to be careful not to assign the
159 * TmpFileStar type to any files that are expected to remain
160 * after the dust has settled!
162 if(so->name){
163 if(!(so->txt = so_file_open(so))){
164 dprint((1, "so_get error: %s : %s",
165 so->name ? so->name : "?",
166 error_description(errno)));
167 if(source == TmpFileStar)
168 our_unlink(so->name);
170 fs_give((void **)&so->name);
171 fs_give((void **)&so); /* so freed & set to NULL */
174 else{
175 if(!(so->txt = (void *) create_tmpfile())){
176 dprint((1, "so_get error: tmpfile : %s",
177 error_description(errno)));
178 fs_give((void **)&so); /* so freed & set to NULL */
182 else if(so->src == ExternalText && etsod.get){
183 so->writec = etsod.writec;
184 so->readc = etsod.readc;
185 so->puts = etsod.puts;
186 if(!(so->txt = (*etsod.get)())){
187 dprint((1, "so_get error: external driver allocation error"));
189 if(so->name)
190 fs_give((void **)&so->name);
192 fs_give((void **)&so); /* so freed & set to NULL */
195 #ifdef SMIME
196 else if(so->src == BioType){
197 so->writec = so_bio_writec;
198 so->readc = so_bio_readc;
199 so->puts = so_bio_puts;
201 if(!(so->txt = BIO_new(BIO_s_mem()))){
202 dprint((1, "so_get error: BIO driver allocation error"));
204 if(so->name)
205 fs_give((void **) &so->name);
207 fs_give((void **) &so); /* so freed & set to NULL */
210 #endif /* SMIME */
211 else{
212 so->writec = (rtype & WRITE_TO_LOCALE) ? so_cs_writec_locale
213 : so_cs_writec;
214 so->readc = (rtype & READ_FROM_LOCALE) ? so_cs_readc_locale
215 : so_cs_readc;
216 so->puts = (rtype & WRITE_TO_LOCALE) ? so_cs_puts_locale
217 : so_cs_puts;
219 so->txt = (void *)fs_get((size_t) MSIZE_INIT * sizeof(char));
220 so->dp = so->eod = (unsigned char *) so->txt;
221 so->eot = so->dp + MSIZE_INIT;
222 memset(so->eod, 0, so->eot - so->eod);
225 return(so);
230 * so_give - free resources associated with a storage object and then
231 * the object itself.
234 so_give(STORE_S **so)
236 int ret = 0;
238 if(!(so && (*so)))
239 return(ret);
241 if((*so)->src == FileStar || (*so)->src == TmpFileStar){
242 if((*so)->txt) /* disassociate from storage */
243 ret = fclose((FILE *)(*so)->txt) == EOF ? -1 : 0;
245 if((*so)->name && (*so)->src == TmpFileStar)
246 our_unlink((*so)->name); /* really disassociate! */
248 else if((*so)->txt && (*so)->src == ExternalText){
249 if(etsod.give)
250 (*etsod.give)((*so)->txt);
252 #ifdef SMIME
253 else if((*so)->txt && (*so)->src == BioType){
254 BIO *b = (BIO *) (*so)->txt;
256 BIO_free(b);
258 #endif /* SMIME */
259 else if((*so)->txt)
260 fs_give((void **)&((*so)->txt));
262 if((*so)->name)
263 fs_give((void **)&((*so)->name)); /* blast the name */
265 /* release attribute list */
266 mail_free_body_parameter(&(*so)->attr);
268 fs_give((void **)so); /* release the object */
270 return(ret);
275 * so_register_external_driver - hokey way to get pico-dependent storage object
276 * support out of pith library
278 void
279 so_register_external_driver(STORE_S *(*get)(void),
280 int (*give)(STORE_S **),
281 int (*writec)(int, STORE_S *),
282 int (*readc)(unsigned char *, STORE_S *),
283 int (*puts)(STORE_S *, char *),
284 int (*seek)(STORE_S *, long int, int),
285 int (*truncate)(STORE_S *, off_t),
286 int (*tell)(STORE_S *))
288 memset(&etsod, 0, sizeof(etsod));
289 if(get)
290 etsod.get = get;
292 if(give)
293 etsod.give = give;
295 if(writec)
296 etsod.writec = writec;
298 if(readc)
299 etsod.readc = readc;
301 if(puts)
302 etsod.puts = puts;
304 if(seek)
305 etsod.seek = seek;
307 if(truncate)
308 etsod.truncate = truncate;
310 if(tell)
311 etsod.tell = tell;
315 void *
316 so_file_open(STORE_S *so)
318 char *type = ((so->flags) & WRITE_ACCESS) ? "a+" : "r";
319 int flags, fd,
320 mode = (((so->flags) & OWNER_ONLY) || so->src == TmpFileStar)
321 ? OP_MD_USER : OP_MD_ALL;
324 * Careful. EDIT_ACCESS and WRITE_TO_LOCALE/READ_FROM_LOCALE will
325 * not work together.
327 if(so->flags & WRITE_ACCESS){
328 flags = O_RDWR | O_CREAT | O_APPEND | O_BINARY;
330 else{
331 flags = O_RDONLY;
332 if(so->flags & READ_FROM_LOCALE){
333 flags |= _O_WTEXT;
335 else{
336 flags |= O_BINARY;
341 * Use open instead of fopen so we can make temp files private.
342 * I believe the "b" or "t" in the type isn't necessary in the fdopen call
343 * because we already set O_BINARY or _O_U8TEXT or _O_WTEXT in the open.
345 return(((fd = our_open(so->name, flags, mode)) > -1)
346 ? (so->txt = (void *) fdopen(fd, type)) : NULL);
351 * put a character into the specified storage object,
352 * expanding if necessary
354 * return 1 on success and 0 on failure
357 so_cs_writec(int c, STORE_S *so)
359 if(so->dp >= so->eot){
360 size_t incr;
361 size_t cur_o = so->dp - (unsigned char *) so->txt;
362 size_t data_o = so->eod - (unsigned char *) so->txt;
363 size_t size = (so->eot - (unsigned char *) so->txt);
366 * We estimate the size we're going to need at the beginning
367 * so it shouldn't normally happen that we run out of space and
368 * come here. If we do come here, it is probably because there
369 * are lots of handles in the message or lots of quote coloring.
370 * In either case, the overhead of those is high so we don't want
371 * to keep adding little bits and resizing. Add 50% each time
372 * instead.
374 incr = MAX(size/2, MSIZE_INC);
375 size += incr;
377 fs_resize(&so->txt, size * sizeof(char));
378 so->dp = (unsigned char *) so->txt + cur_o;
379 so->eod = (unsigned char *) so->txt + data_o;
380 so->eot = (unsigned char *) so->txt + size;
381 memset(so->eod, 0, so->eot - so->eod);
384 *so->dp++ = (unsigned char) c;
385 if(so->dp > so->eod)
386 so->eod = so->dp;
388 return(1);
393 * The locale version converts from UTF-8 to user's locale charset
394 * before writing the characters.
397 so_cs_writec_locale(int c, STORE_S *so)
399 int rv = 1;
400 int i, outchars;
401 unsigned char obuf[MAX(MB_LEN_MAX,32)];
403 if((outchars = utf8_to_locale(c, &so->cb, obuf, sizeof(obuf))) != 0){
404 for(i = 0; i < outchars; i++)
405 if(so_cs_writec(obuf[i], so) != 1){
406 rv = 0;
407 break;
411 return(rv);
416 so_file_writec(int c, STORE_S *so)
418 unsigned char ch = (unsigned char) c;
419 int rv = 0;
421 if(so->txt || so_reaquire(so))
423 rv = fwrite(&ch,sizeof(unsigned char),(size_t)1,(FILE *)so->txt);
424 while(!rv && ferror((FILE *)so->txt) && errno == EINTR);
426 return(rv);
431 * The locale version converts from UTF-8 to user's locale charset
432 * before writing the characters.
435 so_file_writec_locale(int c, STORE_S *so)
437 int rv = 1;
438 int i, outchars;
439 unsigned char obuf[MAX(MB_LEN_MAX,32)];
441 if((outchars = utf8_to_locale(c, &so->cb, obuf, sizeof(obuf))) != 0){
442 for(i = 0; i < outchars; i++)
443 if(so_file_writec(obuf[i], so) != 1){
444 rv = 0;
445 break;
449 return(rv);
454 * get a character from the specified storage object.
456 * return 1 on success and 0 on failure
459 so_cs_readc(unsigned char *c, STORE_S *so)
461 return((so->dp < so->eod) ? *c = *(so->dp)++, 1 : 0);
466 * The locale version converts from user's locale charset to UTF-8
467 * after reading the characters and before returning to the caller.
470 so_cs_readc_locale(unsigned char *c, STORE_S *so)
472 return(generic_readc_locale(c, so_cs_readc_getchar, so, &so->cb));
477 so_cs_readc_getchar(unsigned char *c, void *extraarg)
479 STORE_S *so;
481 so = (STORE_S *) extraarg;
482 return(so_cs_readc(c, so));
487 so_file_readc(unsigned char *c, STORE_S *so)
489 int rv = 0;
491 if(so->txt || so_reaquire(so))
493 rv = fread(c, sizeof(char), (size_t)1, (FILE *)so->txt);
494 while(!rv && ferror((FILE *)so->txt) && errno == EINTR);
496 return(rv);
501 * The locale version converts from user's locale charset to UTF-8
502 * after reading the characters and before returning to the caller.
505 so_file_readc_locale(unsigned char *c, STORE_S *so)
507 return(generic_readc_locale(c, so_file_readc_getchar, so, &so->cb));
512 so_file_readc_getchar(unsigned char *c, void *extraarg)
514 STORE_S *so;
516 so = (STORE_S *) extraarg;
517 return(so_file_readc(c, so));
521 #ifdef _WINDOWS
523 * Read unicode characters from windows filesystem and return
524 * them as a stream of UTF-8 characters. The stream is assumed
525 * opened so that it will know how to put together the unicode.
528 so_file_readc_windows(unsigned char *c, STORE_S *so)
530 int rv = 0;
531 UCS ucs;
533 /* already got some from previous call? */
534 if(so->cb.cbufend > so->cb.cbuf){
535 *c = *so->cb.cbufp;
536 so->cb.cbufp++;
537 rv++;
538 if(so->cb.cbufp >= so->cb.cbufend){
539 so->cb.cbufend = so->cb.cbuf;
540 so->cb.cbufp = so->cb.cbuf;
543 return(rv);
546 if(so->txt || so_reaquire(so)){
547 /* windows only so second arg is ignored */
548 ucs = read_a_wide_char((FILE *) so->txt, NULL);
549 rv = (ucs == CCONV_EOF) ? 0 : 1;
552 if(rv){
554 * Now we need to convert the UCS character to UTF-8
555 * and dole out the UTF-8 one char at a time.
557 so->cb.cbufend = utf8_put(so->cb.cbuf, (unsigned long) ucs);
558 so->cb.cbufp = so->cb.cbuf;
559 if(so->cb.cbufend > so->cb.cbuf){
560 *c = *so->cb.cbufp;
561 so->cb.cbufp++;
562 if(so->cb.cbufp >= so->cb.cbufend){
563 so->cb.cbufend = so->cb.cbuf;
564 so->cb.cbufp = so->cb.cbuf;
567 else
568 *c = '?';
571 return(rv);
573 #endif /* _WINDOWS */
577 * write a string into the specified storage object,
578 * expanding if necessary (and cheating if the object
579 * happens to be a file!)
581 * return 1 on success and 0 on failure
584 so_cs_puts(STORE_S *so, char *s)
586 int slen = strlen(s);
588 if(so->dp + slen >= so->eot){
589 register size_t cur_o = so->dp - (unsigned char *) so->txt;
590 register size_t data_o = so->eod - (unsigned char *) so->txt;
591 register size_t len = so->eot - (unsigned char *) so->txt;
592 while(len <= cur_o + slen + 1){
593 size_t incr;
595 incr = MAX(len/2, MSIZE_INC);
596 len += incr;
599 fs_resize(&so->txt, len * sizeof(char));
600 so->dp = (unsigned char *)so->txt + cur_o;
601 so->eod = (unsigned char *)so->txt + data_o;
602 so->eot = (unsigned char *)so->txt + len;
603 memset(so->eod, 0, so->eot - so->eod);
606 memcpy(so->dp, s, slen);
607 so->dp += slen;
608 if(so->dp > so->eod)
609 so->eod = so->dp;
611 return(1);
616 so_cs_puts_locale(STORE_S *so, char *s)
618 int slen = strlen(s);
620 while(slen--)
621 if(!so_cs_writec_locale((unsigned char) *s++, so))
622 return(0);
624 return(1);
629 so_file_puts(STORE_S *so, char *s)
631 int rv = *s ? 0 : 1;
633 if(!rv && (so->txt || so_reaquire(so)))
635 rv = fwrite(s, strlen(s)*sizeof(char), (size_t)1, (FILE *)so->txt);
636 while(!rv && ferror((FILE *)so->txt) && errno == EINTR);
638 return(rv);
643 so_file_puts_locale(STORE_S *so, char *s)
645 int slen = strlen(s);
647 while(slen--)
648 if(!so_file_writec_locale((unsigned char) *s++, so))
649 return(0);
651 return(1);
655 #ifdef SMIME
657 * put a character into the specified storage object,
658 * expanding if necessary
660 * return 1 on success and 0 on failure
663 so_bio_writec(int c, STORE_S *so)
665 if(so->txt && so->src == BioType){
666 unsigned char ch[1];
667 BIO *b = (BIO *) so->txt;
669 ch[0] = (unsigned char) (c & 0xff);
671 if(BIO_write(b, ch, 1) >= 1)
672 return(1);
675 return(0);
680 so_bio_readc(unsigned char *c, STORE_S *so)
682 if(so->txt && so->src == BioType){
683 unsigned char ch[1];
684 BIO *b = (BIO *) so->txt;
686 if(BIO_read(b, ch, 1) >= 1){
687 *c = ch[0];
688 return(1);
692 return(0);
697 * write a string into the specified storage object,
698 * expanding if necessary (and cheating if the object
699 * happens to be a file!)
701 * return 1 on success and 0 on failure
704 so_bio_puts(STORE_S *so, char *s)
707 if(so->txt && so->src == BioType){
708 BIO *b = (BIO *) so->txt;
709 int slen = strlen(s);
711 if(BIO_puts(b, s) >= slen)
712 return(1);
715 return(1);
717 #endif /* SMIME */
724 so_nputs(STORE_S *so, char *s, long int n)
726 while(n--)
727 if(!so_writec((unsigned char) *s++, so))
728 return(0); /* ERROR putting char ! */
730 return(1);
735 * Position the storage object's pointer to the given offset
736 * from the start of the object's data.
739 so_seek(STORE_S *so, long int pos, int orig)
741 if(so->src == CharStar){
742 switch(orig){
743 case 0 : /* SEEK_SET */
744 return((pos < so->eod - (unsigned char *) so->txt)
745 ? so->dp = (unsigned char *)so->txt + pos, 0 : -1);
746 case 1 : /* SEEK_CUR */
747 return((pos > 0)
748 ? ((pos < so->eod - so->dp) ? so->dp += pos, 0: -1)
749 : ((pos < 0)
750 ? ((-pos < so->dp - (unsigned char *)so->txt)
751 ? so->dp += pos, 0 : -1)
752 : 0));
753 case 2 : /* SEEK_END */
754 return((pos > 0)
755 ? -1
756 : ((-pos <= so->eod - (unsigned char *) so->txt)
757 ? so->dp = so->eod + pos, 0 : -1));
758 default :
759 return(-1);
762 else if(so->src == ExternalText){
763 if(etsod.seek)
764 return((*etsod.seek)(so->txt, pos, orig));
766 fatal("programmer botch: unsupported so_seek call");
767 /*NOTREACHED*/
768 return(0); /* suppress dumb compiler warnings */
770 #ifdef SMIME
771 else if(so->src == BioType){
772 BIO *b = (BIO *) so->txt;
774 if(b && BIO_method_type(b) != BIO_TYPE_MEM)
775 (void) BIO_reset(b);
777 return(0);
779 #endif /* SMIME */
780 else /* FileStar or TmpFileStar */
781 return((so->txt || so_reaquire(so))
782 ? fseek((FILE *)so->txt,pos,orig)
783 : -1);
788 * Change the given storage object's size to that specified. If size
789 * is less than the current size, the internal pointer is adjusted and
790 * all previous data beyond the given size is lost.
792 * Returns 0 on failure.
795 so_truncate(STORE_S *so, long int size)
797 if(so->src == CharStar){
798 if(so->eod < (unsigned char *) so->txt + size){ /* alloc! */
799 unsigned char *newtxt = (unsigned char *) so->txt;
800 register size_t len = so->eot - (unsigned char *) so->txt;
802 while(len <= size)
803 len += MSIZE_INC; /* need to resize! */
805 if(len > so->eot - (unsigned char *) newtxt){
806 fs_resize((void **) &newtxt, len * sizeof(char));
807 so->eot = newtxt + len;
808 so->eod = newtxt + (so->eod - (unsigned char *) so->txt);
809 memset(so->eod, 0, so->eot - so->eod);
812 so->eod = newtxt + size;
813 so->dp = newtxt + (so->dp - (unsigned char *) so->txt);
814 so->txt = newtxt;
816 else if(so->eod > (unsigned char *) so->txt + size){
817 if(so->dp > (so->eod = (unsigned char *)so->txt + size))
818 so->dp = so->eod;
820 memset(so->eod, 0, so->eot - so->eod);
823 return(1);
825 else if(so->src == ExternalText){
826 if(etsod.truncate)
827 return((*etsod.truncate)(so, (off_t) size));
829 fatal("programmer botch: unsupported so_truncate call");
830 /*NOTREACHED*/
831 return(0); /* suppress dumb compiler warnings */
833 #ifdef SMIME
834 else if(so->src == BioType){
835 fatal("programmer botch: unsupported so_truncate call for BioType");
836 /*NOTREACHED*/
837 return(0); /* suppress dumb compiler warnings */
839 #ifdef notdef
840 long len;
841 BIO *b = (BIO *) so->txt;
843 if(b){
844 BUF_MEM *biobuf = NULL;
846 BIO_get_mem_ptr(b, &biobuf);
847 if(biobuf){
848 BUF_MEM_grow(biobuf, size);
849 return(1);
853 return(0);
854 #endif /* notdef */
856 #endif /* SMIME */
857 else /* FileStar or TmpFileStar */
858 return(fflush((FILE *) so->txt) != EOF
859 && fseek((FILE *) so->txt, size, 0) == 0
860 && ftruncate(fileno((FILE *)so->txt), (off_t) size) == 0);
865 * Report given storage object's position indicator.
866 * Returns 0 on failure.
868 long
869 so_tell(STORE_S *so)
871 if(so->src == CharStar){
872 return((long) (so->dp - (unsigned char *) so->txt));
874 else if(so->src == ExternalText){
875 if(etsod.tell)
876 return((*etsod.tell)(so));
878 fatal("programmer botch: unsupported so_tell call");
879 /*NOTREACHED*/
880 return(0); /* suppress dumb compiler warnings */
882 #ifdef SMIME
883 else if(so->src == BioType){
884 fatal("programmer botch: unsupported so_tell call for BioType");
885 /*NOTREACHED*/
886 return(0); /* suppress dumb compiler warnings */
888 #endif /* SMIME */
889 else /* FileStar or TmpFileStar */
890 return(ftell((FILE *) so->txt));
895 * so_attr - hook to hang random attributes onto the storage object
897 char *
898 so_attr(STORE_S *so, char *key, char *value)
900 if(so && key){
901 if(value){
902 PARAMETER **pp = &so->attr;
904 while(1){
905 if(*pp){
906 if((*pp)->attribute && !strcmp(key, (*pp)->attribute)){
907 if((*pp)->value)
908 fs_give((void **)&(*pp)->value);
910 break;
913 pp = &(*pp)->next;
915 else{
916 *pp = mail_newbody_parameter();
917 (*pp)->attribute = cpystr(key);
918 break;
922 return((*pp)->value = cpystr(value));
924 else{
925 PARAMETER *p;
927 for(p = so->attr; p; p = p->next)
928 if(p->attribute && !strcmp(key, p->attribute))
929 return(p->value);
933 return(NULL);
938 * so_release - a rather misnamed function. the idea is to release
939 * what system resources we can (e.g., open files).
940 * while maintaining a reference to it.
941 * it's up to the functions that deal with this object
942 * next to re-aquire those resources.
945 so_release(STORE_S *so)
947 if(so->txt && so->name && (so->src == FileStar || so->src == TmpFileStar)){
948 if(fget_pos((FILE *)so->txt, (fpos_t *)&(so->used)) == 0){
949 fclose((FILE *)so->txt); /* free the handle! */
950 so->txt = NULL;
954 return(1);
959 * so_reaquire - get any previously released system resources we
960 * may need for the given storage object.
961 * NOTE: at the moment, only FILE * types of objects are
962 * effected, so it only needs to be called before
963 * references to them.
967 so_reaquire(STORE_S *so)
969 int rv = 1;
971 if(!so->txt && (so->src == FileStar || so->src == TmpFileStar)){
972 if(!(so->txt = so_file_open(so))){
973 q_status_message2(SM_ORDER,3,5, "ERROR reopening %.200s : %.200s",
974 so->name, error_description(errno));
975 rv = 0;
977 else if(fset_pos((FILE *)so->txt, (fpos_t *)&(so->used))){
978 q_status_message2(SM_ORDER, 3, 5,
979 "ERROR positioning in %.200s : %.200s",
980 so->name, error_description(errno));
981 rv = 0;
985 return(rv);
990 * so_text - return a pointer to the text the store object passed
992 void *
993 so_text(STORE_S *so)
995 return((so) ? so->txt : NULL);
1000 * Similar to fgets but reading from a storage object.
1002 char *
1003 so_fgets(STORE_S *so, char *s, size_t size)
1005 unsigned char c;
1006 char *p = s;
1008 while(--size > 0 && so_readc(&c, so) > 0){
1009 *p++ = (char) c;
1010 if(c == '\n')
1011 break;
1014 *p = '\0';
1016 return((p>s) ? s : NULL);