"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.1/src/rfc1524.c" (12 Oct 2016, 14526 Bytes) of package /linux/misc/tin-2.4.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rfc1524.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.0_vs_2.4.1.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : rfc1524.c
    4  *  Author    : Urs Janssen <urs@tin.org>, Jason Faultless <jason@altarstone.com>
    5  *  Created   : 2000-05-15
    6  *  Updated   : 2013-11-21
    7  *  Notes     : mailcap parsing as defined in RFC 1524
    8  *
    9  * Copyright (c) 2000-2017 Urs Janssen <urs@tin.org>, Jason Faultless <jason@altarstone.com>
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. The name of the author may not be used to endorse or promote
   21  *    products derived from this software without specific prior written
   22  *    permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS
   25  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
   28  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   30  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   35  */
   36 
   37 #ifndef TIN_H
   38 #   include "tin.h"
   39 #endif /* !TIN_H */
   40 
   41 
   42 /*
   43  * As defined in RFC 1524, Appendix A
   44  * TODO: what about !unix systems?
   45  */
   46 #define DEFAULT_MAILCAPS "~/.mailcap:/etc/mailcap:/usr/etc/mailcap:/usr/local/etc/mailcap:/etc/mail/mailcap"
   47 
   48 /* maximum number of mailcap fields */
   49 #define MAILCAPFIELDS 13
   50 
   51 /* local prototypes */
   52 static char *expand_mailcap_meta(const char *mailcap, t_part *part, t_bool escape_shell_meta_chars, const char *path);
   53 static char *get_mailcap_field(char *mailcap);
   54 static t_mailcap *parse_mailcap_line(const char *mailcap, t_part *part, const char *path);
   55 
   56 
   57 /*
   58  * mainloop:
   59  *  scan mailcap file(s), look for a matching entry, extract fields,
   60  *  expand metas
   61  *
   62  * TODO: don't used fixed length buffers
   63  */
   64 t_mailcap *
   65 get_mailcap_entry(
   66     t_part *part,
   67     const char *path)
   68 {
   69     FILE *fp;
   70     char *ptr, *ptr2, *nptr;
   71     char buf[LEN];
   72     char filename[LEN]; /* name of current mailcap file */
   73     char mailcap[LEN];  /* full match */
   74     char *mailcaps = NULL;  /* possible mailcap files */
   75     char wildcap[LEN];  /* basetype match */
   76     t_mailcap *foo = (t_mailcap *) 0;
   77 
   78     /* build list of mailcap files */
   79     if ((ptr = getenv("MAILCAPS")) != NULL && strlen(ptr))
   80         mailcaps = my_strdup(ptr);
   81     if (mailcaps != NULL) {
   82         mailcaps = my_realloc(mailcaps, strlen(mailcaps) + strlen(DEFAULT_MAILCAPS) + 2);
   83         strcat(strcat(mailcaps, ":"), DEFAULT_MAILCAPS);
   84     } else
   85         mailcaps = my_strdup(DEFAULT_MAILCAPS);
   86 
   87     mailcap[0] = '\0';
   88     wildcap[0] = '\0';
   89     buf[0] = '\0';
   90 
   91     ptr = buf;
   92 
   93     nptr = strtok(mailcaps, ":");
   94     while (nptr != NULL) {
   95         /* expand ~ and/or $HOME etc. */
   96         if (strfpath(nptr, filename, sizeof(filename) - 1, &CURR_GROUP, FALSE)) {
   97             if ((fp = fopen(filename, "r")) != NULL) {
   98                 while ((fgets(ptr, sizeof(buf) - strlen(buf), fp)) != NULL) {
   99                     if (*ptr == '#' || *ptr == '\n')        /* skip comments & blank lines */
  100                         continue;
  101 
  102                     ptr = buf + strlen(buf) - 1;
  103 
  104                     if (*ptr == '\n')       /* remove linebreaks */
  105                         *ptr-- = '\0';
  106 
  107                     if (*ptr == '\\')       /* continuation line */
  108                         continue;           /* append */
  109                     else
  110                         ptr = buf;
  111 
  112                     if ((ptr2 = strchr(buf, '/')) != NULL) {
  113                         if (!strncasecmp(ptr, content_types[part->type], strlen(ptr) - strlen(ptr2))) {
  114                             if (!strncasecmp(ptr + strlen(content_types[part->type]) + 1, part->subtype, strlen(part->subtype))) {
  115                                 /* full match, so parse line and evaluate test if given. */
  116                                 STRCPY(mailcap, ptr);
  117                                 FreeAndNull(foo);
  118                                 foo = parse_mailcap_line(mailcap, part, path);
  119                                 if (foo != NULL) {
  120                                     fclose(fp); /* perfect match with test succeeded (if given) */
  121                                     free(mailcaps);
  122                                     return foo;
  123                                 }
  124                             } else {
  125                                 if ((*(ptr2 + 1) == '*') || (*(ptr2 + 1) == ';')) { /* wildmat match */
  126                                     if (!strlen(wildcap)) { /* we don't already have a wildmat match */
  127                                         STRCPY(wildcap, buf);
  128                                         FreeAndNull(foo);
  129                                         foo = parse_mailcap_line(wildcap, part, path);
  130                                         if (foo == NULL) /* test failed */
  131                                             wildcap[0] = '\0'; /* ignore match */
  132                                     }
  133                                 } /* else subtype mismatch, no action required */
  134                             }
  135                         } /* else no match, no action required */
  136                     } /* else invalid mailcap line (no /), no action required */
  137                     if (strlen(wildcap)) {  /* we just had a wildmat match */
  138                         fclose(fp);
  139                         free(mailcaps);
  140                         return foo;
  141                     }
  142                 } /* while ((fgets(ptr, ... */
  143                 fclose(fp);
  144             }
  145         } /* else strfpath() failed, no action required */
  146         nptr = strtok(NULL, ":"); /* get next filename */
  147     }
  148     free(mailcaps);
  149     FreeAndNull(foo);
  150     return foo;
  151 }
  152 
  153 
  154 /*
  155  * extract fields, expand metas - called from get_mailcap_entry()
  156  */
  157 static t_mailcap*
  158 parse_mailcap_line(
  159     const char *mailcap,
  160     t_part *part,
  161     const char *path)
  162 {
  163     char *ptr, *optr, *buf;
  164     int i = MAILCAPFIELDS - 2; /* max MAILCAPFIELDS - required fileds */
  165     t_mailcap *tmailcap;
  166 
  167     /* malloc and init */
  168     tmailcap = my_malloc(sizeof(t_mailcap));
  169     tmailcap->type = NULL;
  170     tmailcap->command = NULL;
  171     tmailcap->needsterminal = FALSE;
  172     tmailcap->copiousoutput = FALSE;
  173     tmailcap->textualnewlines = 0;
  174     tmailcap->description = NULL;
  175     tmailcap->test = NULL;
  176     tmailcap->nametemplate = NULL;
  177     tmailcap->compose = NULL;
  178     tmailcap->composetyped = NULL;
  179     tmailcap->edit = NULL;
  180     tmailcap->print = NULL;
  181     tmailcap->x11bitmap = NULL;
  182 
  183     optr = ptr = my_strdup(mailcap);
  184 
  185     /* get required entrys */
  186     ptr = get_mailcap_field(ptr);
  187     buf = my_calloc(1, strlen(content_types[part->type]) + strlen(part->subtype) + 2);
  188     sprintf(buf, "%s/%s", content_types[part->type], part->subtype);
  189     tmailcap->type = buf;
  190     ptr += strlen(ptr) + 1;
  191     if ((ptr = get_mailcap_field(ptr)) != NULL) {
  192         tmailcap->command = ptr;
  193         ptr += strlen(ptr) + 1;
  194     } else { /* required filed missing */
  195         free(optr);
  196         free_mailcap(tmailcap);
  197         return ((t_mailcap *) 0);
  198     }
  199 
  200     while ((ptr = get_mailcap_field(ptr)) != NULL) {
  201         if (i-- <= 0) /* number of possible fields exhausted */
  202             break;
  203         if (!strncasecmp(ptr, "needsterminal", 13)) {
  204             tmailcap->needsterminal = TRUE;
  205             ptr += strlen(ptr) + 1;
  206         }
  207         if (!strncasecmp(ptr, "copiousoutput", 13)) {
  208             tmailcap->copiousoutput = TRUE;
  209             ptr += strlen(ptr) + 1;
  210         }
  211         if (!strncasecmp(ptr, "description=", 12)) {
  212             tmailcap->description = ptr + 12;
  213             ptr += strlen(ptr) + 1;
  214         }
  215         if (!strncasecmp(ptr, "nametemplate=", 13)) {
  216             tmailcap->nametemplate = expand_mailcap_meta(ptr + 13, part, FALSE, path);
  217             ptr += strlen(ptr) + 1;
  218         }
  219         if (!strncasecmp(ptr, "test=", 5)) {
  220             tmailcap->test = ptr + 5;
  221             ptr += strlen(ptr) + 1;
  222         }
  223         if (!strncasecmp(ptr, "textualnewlines=", 16)) {
  224             tmailcap->textualnewlines = atoi(ptr + 16);
  225             ptr += strlen(ptr) + 1;
  226         }
  227         if (!strncasecmp(ptr, "compose=", 8)) {
  228             tmailcap->compose = ptr + 8;
  229             ptr += strlen(ptr) + 1;
  230         }
  231         if (!strncasecmp(ptr, "composetyped=", 13)) {
  232             tmailcap->composetyped = ptr + 13;
  233             ptr += strlen(ptr) + 1;
  234         }
  235         if (!strncasecmp(ptr, "edit=", 5)) {
  236             tmailcap->edit = ptr + 5;
  237             ptr += strlen(ptr) + 1;
  238         }
  239         if (!strncasecmp(ptr, "print=", 6)) {
  240             tmailcap->print = ptr + 6;
  241             ptr += strlen(ptr) + 1;
  242         }
  243         if (!strncasecmp(ptr, "x11-bitmap=", 11)) {
  244             tmailcap->x11bitmap = ptr + 11;
  245             ptr += strlen(ptr) + 1;
  246         }
  247     }
  248 
  249     /*
  250      * expand metas - we do it in a 2nd pass to be able to honor
  251      * nametemplate
  252      */
  253     if (tmailcap->command != NULL)
  254         tmailcap->command = expand_mailcap_meta(tmailcap->command, part, TRUE, tmailcap->nametemplate ? tmailcap->nametemplate : path);
  255     if (tmailcap->description != NULL)
  256         tmailcap->description = expand_mailcap_meta(tmailcap->description, part, FALSE, tmailcap->nametemplate ? tmailcap->nametemplate : path);
  257     if (tmailcap->test != NULL)
  258         tmailcap->test = expand_mailcap_meta(tmailcap->test, part, TRUE, tmailcap->nametemplate ? tmailcap->nametemplate : path);
  259     if (tmailcap->compose != NULL)
  260         tmailcap->compose = expand_mailcap_meta(tmailcap->compose, part, TRUE, tmailcap->nametemplate ? tmailcap->nametemplate : path);
  261     if (tmailcap->composetyped != NULL)
  262         tmailcap->composetyped = expand_mailcap_meta(tmailcap->composetyped, part, TRUE, tmailcap->nametemplate ? tmailcap->nametemplate : path);
  263     if (tmailcap->edit != NULL)
  264         tmailcap->edit = expand_mailcap_meta(tmailcap->edit, part, TRUE, tmailcap->nametemplate ? tmailcap->nametemplate : path);
  265     if (tmailcap->print != NULL)
  266         tmailcap->print = expand_mailcap_meta(tmailcap->print, part, TRUE, tmailcap->nametemplate ? tmailcap->nametemplate : path);
  267     if (tmailcap->x11bitmap != NULL)
  268         tmailcap->x11bitmap = expand_mailcap_meta(tmailcap->x11bitmap, part, TRUE, tmailcap->nametemplate ? tmailcap->nametemplate : path);
  269 
  270     free(optr);
  271 
  272     if (tmailcap->test != NULL) { /* test field given */
  273         /*
  274          * TODO: EndWin()/InitWin() around system needed?
  275          *       use invoke_cmd()?
  276          */
  277         if (system(tmailcap->test)) { /* test failed? */
  278             free_mailcap(tmailcap);
  279             return ((t_mailcap *) 0);
  280         }
  281     }
  282     return tmailcap;
  283 }
  284 
  285 
  286 /*
  287  * extract fields - called from parse_mailcap_line()
  288  *
  289  * TODO: add handling for singlequotes
  290  */
  291 static char *
  292 get_mailcap_field(
  293     char *mailcap)
  294 {
  295     char *ptr;
  296     t_bool backquote = FALSE;
  297     t_bool doublequote = FALSE;
  298 
  299     ptr = str_trim(mailcap);
  300 
  301     while (*ptr != '\0') {
  302         switch (*ptr) {
  303             case '\\':
  304                 backquote = bool_not(backquote);
  305                 break;
  306 
  307             case '"':
  308                 if (!backquote)
  309                     doublequote = bool_not(doublequote);
  310                 backquote = FALSE;
  311                 break;
  312 
  313             case ';':
  314                 if (!backquote && !doublequote) { /* field separator (plain ;) */
  315                     *ptr = '\0';
  316                     return mailcap;
  317                 }
  318                 if (backquote && !doublequote) /* remove \ in \; if not inside "" or '' */
  319                     *(ptr - 1) = ' ';
  320                 backquote = FALSE;
  321                 break;
  322 
  323             default:
  324                 backquote = FALSE;
  325                 break;
  326         }
  327         ptr++;
  328     }
  329     return mailcap;
  330 }
  331 
  332 
  333 #define CHECK_SPACE(minlen) { \
  334     while (space <= (minlen)) { /* need more space? */ \
  335         olen = strlen(line); \
  336         space += linelen; \
  337         linelen <<= 1; \
  338         line = my_realloc(line, linelen); \
  339         memset(line + olen, 0, linelen - olen); \
  340     } \
  341 }
  342 
  343 
  344 /*
  345  * expand metas - called from parse_mailcap_line()
  346  *
  347  * TODO: expand %F, %n
  348  */
  349 static char *
  350 expand_mailcap_meta(
  351     const char *mailcap,
  352     t_part *part,
  353     t_bool escape_shell_meta_chars,
  354     const char *path)
  355 {
  356     const char *ptr;
  357     char *line, *lptr;
  358     int quote = no_quote;
  359     size_t linelen, space, olen;
  360 
  361     if (!(strchr(mailcap, '%'))) /* nothing to expand */
  362         return my_strdup(mailcap); /* waste of mem, but simplyfies the frees */
  363 
  364     linelen = LEN * 2;                  /* initial maxlen */
  365     space = linelen - 1;                    /* available space in string */
  366     line = my_calloc(1, linelen);
  367     lptr = line;
  368     ptr = mailcap;
  369 
  370     while (*ptr != '\0') {
  371         /*
  372          * to avoid reallocs() for the all the single char cases
  373          * we do a check here
  374          */
  375         if (space < 10) {               /* 'worst'case are two chars ... */
  376             olen = strlen(line);        /* get current legth of string */
  377             space += linelen;           /* recalc available space */
  378             linelen <<= 1;              /* double maxlen */
  379             line = my_realloc(line, linelen);
  380             memset(line + olen, 0, linelen - olen); /* weed out junk */
  381             lptr = line + olen;     /* adjust pointer to current position */
  382         }
  383 
  384         if ('\\' == *ptr) {
  385             ptr++;
  386             if (('\\' == *ptr) || ('%' == *ptr)) {
  387                 *lptr++ = *ptr++;
  388                 space--;
  389             }
  390             continue;
  391         }
  392         if ('%' == *ptr) {
  393             ptr++;
  394             if ('{' == *ptr) {  /* Content-Type parameter */
  395                 char *end;
  396 
  397                 if ((end = strchr(ptr, '}')) != NULL) {
  398                     if (part->params != NULL) {
  399                         char *parameter;
  400                         const char *value;
  401 
  402                         parameter = my_calloc(1, end - ptr + 1);
  403                         strncpy(parameter, ptr + 1, end - ptr - 1); /* extract parameter name */
  404                         if ((value = get_param(part->params, parameter)) != NULL) { /* match? */
  405                             const char *nptr = escape_shell_meta_chars ? escape_shell_meta(value, quote) : value;
  406 
  407                             CHECK_SPACE(strlen(nptr));
  408                             strcat(line, nptr);
  409                             lptr = line + strlen(line);
  410                             space -= strlen(line);
  411                         }
  412                         free(parameter);
  413                     }
  414                     ptr = end;  /* skip past closing } */
  415                     ptr++;
  416                 } else {
  417                     /* sequence broken, output literally */
  418                     *lptr++ = '%';
  419                     *lptr++ = *ptr++;
  420                     space -= 2;
  421                 }
  422                 continue;
  423 #if 0 /* TODO */
  424             } else if ('F' == *ptr) {   /* Content-Types and Filenames of sub parts */
  425             } else if ('n' == *ptr) {   /* Number of sub parts */
  426             }
  427 #endif /* 0 */
  428             } else if ('s' == *ptr) {   /* Filename */
  429                 const char *nptr = escape_shell_meta_chars ? escape_shell_meta(path, quote) : path;
  430 
  431                 CHECK_SPACE(strlen(nptr) + 2);
  432                 strcat(line, nptr);
  433                 lptr = line + strlen(line);
  434                 space -= strlen(line);
  435                 ptr++;
  436                 continue;
  437             } else if ('t' == *ptr) {   /* Content-Type */
  438                 const char *nptr = escape_shell_meta_chars ? escape_shell_meta(part->subtype, quote) : part->subtype;
  439 
  440                 CHECK_SPACE((strlen(content_types[part->type]) + 1 + strlen(nptr)));
  441                 strcat(line, content_types[part->type]);
  442                 strcat(line, "/");
  443                 strcat(line, nptr);
  444                 lptr = line + strlen(line);
  445                 space -= strlen(line);
  446                 ptr++;
  447                 continue;
  448             } else {    /* unknown % sequence */
  449                 *lptr++ = '%';
  450                 space--;
  451                 continue;
  452             }
  453         }
  454 
  455         if (escape_shell_meta_chars) {
  456             if (('\'' == *ptr) && (quote != dbl_quote))
  457                 quote = (quote == no_quote ? sgl_quote : no_quote);
  458             else if (('"' == *ptr) && (quote != sgl_quote))
  459                 quote = (quote == no_quote ? dbl_quote : no_quote);
  460         }
  461 
  462         /* any other char */
  463         *lptr++ = *ptr++;
  464         space--;
  465     }
  466     return line;
  467 }
  468 
  469 
  470 /*
  471  * frees the malloced space
  472  */
  473 void
  474 free_mailcap(
  475     t_mailcap *tmailcap)
  476 {
  477     FreeIfNeeded(tmailcap->type);
  478     FreeIfNeeded(tmailcap->command);
  479     FreeIfNeeded(tmailcap->compose);
  480     FreeIfNeeded(tmailcap->composetyped);
  481     FreeIfNeeded(tmailcap->description);
  482     FreeIfNeeded(tmailcap->edit);
  483     FreeIfNeeded(tmailcap->nametemplate);
  484     FreeIfNeeded(tmailcap->print);
  485     FreeIfNeeded(tmailcap->test);
  486     FreeIfNeeded(tmailcap->x11bitmap);
  487     free(tmailcap);
  488 }