Logo Search packages:      
Sourcecode: w3m version File versions  Download package

mailcap.c

/* $Id: mailcap.c,v 1.12 2003/01/17 17:06:04 ukai Exp $ */
#include "fm.h"
#include "myctype.h"
#include <stdio.h>
#include <errno.h>
#include "parsetag.h"
#include "local.h"

static struct mailcap DefaultMailcap[] = {
    {"image/*", DEF_IMAGE_VIEWER " %s", 0, NULL, NULL, NULL},     /* */
    {"audio/basic", DEF_AUDIO_PLAYER " %s", 0, NULL, NULL, NULL},
    {NULL, NULL, 0, NULL, NULL, NULL}
};

static TextList *mailcap_list;
static struct mailcap **UserMailcap;

int
mailcapMatch(struct mailcap *mcap, char *type)
{
    char *cap = mcap->type, *p;
    int level;
    for (p = cap; *p != '/'; p++) {
      if (TOLOWER(*p) != TOLOWER(*type))
          return 0;
      type++;
    }
    if (*type != '/')
      return 0;
    p++;
    type++;
    if (mcap->flags & MAILCAP_HTMLOUTPUT)
      level = 1;
    else
      level = 0;
    if (*p == '*')
      return 10 + level;
    while (*p) {
      if (TOLOWER(*p) != TOLOWER(*type))
          return 0;
      p++;
      type++;
    }
    if (*type != '\0')
      return 0;
    return 20 + level;
}

struct mailcap *
searchMailcap(struct mailcap *table, char *type)
{
    int level = 0;
    struct mailcap *mcap = NULL;
    int i;

    if (table == NULL)
      return NULL;
    for (; table->type; table++) {
      i = mailcapMatch(table, type);
      if (i > level) {
          if (table->test) {
            Str command =
                unquote_mailcap(table->test, type, NULL, NULL, NULL);
            if (system(command->ptr) != 0)
                continue;
          }
          level = i;
          mcap = table;
      }
    }
    return mcap;
}

static int
matchMailcapAttr(char *p, char *attr, int len, Str *value)
{
    int quoted;
    char *q = NULL;

    if (strncasecmp(p, attr, len) == 0) {
      p += len;
      SKIP_BLANKS(p);
      if (value) {
          *value = Strnew();
          if (*p == '=') {
            p++;
            SKIP_BLANKS(p);
            quoted = 0;
            while (*p && (quoted || *p != ';')) {
                if (quoted || !IS_SPACE(*p))
                  q = p;
                if (quoted)
                  quoted = 0;
                else if (*p == '\\')
                  quoted = 1;
                Strcat_char(*value, *p);
                p++;
            }
            if (q)
                Strshrink(*value, p - q - 1);
          }
          return 1;
      }
      else {
          if (*p == '\0' || *p == ';') {
            return 1;
          }
      }
    }
    return 0;
}

static int
extractMailcapEntry(char *mcap_entry, struct mailcap *mcap)
{
    int j, k;
    char *p;
    int quoted;
    Str tmp;

    bzero(mcap, sizeof(struct mailcap));
    p = mcap_entry;
    SKIP_BLANKS(p);
    k = -1;
    for (j = 0; p[j] && p[j] != ';'; j++) {
      if (!IS_SPACE(p[j]))
          k = j;
    }
    mcap->type = allocStr(p, (k >= 0) ? k + 1 : j);
    if (!p[j])
      return 0;
    p += j + 1;

    SKIP_BLANKS(p);
    k = -1;
    quoted = 0;
    for (j = 0; p[j] && (quoted || p[j] != ';'); j++) {
      if (quoted || !IS_SPACE(p[j]))
          k = j;
      if (quoted)
          quoted = 0;
      else if (p[j] == '\\')
          quoted = 1;
    }
    mcap->viewer = allocStr(p, (k >= 0) ? k + 1 : j);
    p += j;

    while (*p == ';') {
      p++;
      SKIP_BLANKS(p);
      if (matchMailcapAttr(p, "needsterminal", 13, NULL)) {
          mcap->flags |= MAILCAP_NEEDSTERMINAL;
      }
      else if (matchMailcapAttr(p, "copiousoutput", 13, NULL)) {
          mcap->flags |= MAILCAP_COPIOUSOUTPUT;
      }
      else if (matchMailcapAttr(p, "x-htmloutput", 12, NULL) ||
             matchMailcapAttr(p, "htmloutput", 10, NULL)) {
          mcap->flags |= MAILCAP_HTMLOUTPUT;
      }
      else if (matchMailcapAttr(p, "test", 4, &tmp)) {
          mcap->test = allocStr(tmp->ptr, tmp->length);
      }
      else if (matchMailcapAttr(p, "nametemplate", 12, &tmp)) {
          mcap->nametemplate = allocStr(tmp->ptr, tmp->length);
      }
      else if (matchMailcapAttr(p, "edit", 4, &tmp)) {
          mcap->edit = allocStr(tmp->ptr, tmp->length);
      }
      quoted = 0;
      while (*p && (quoted || *p != ';')) {
          if (quoted)
            quoted = 0;
          else if (*p == '\\')
            quoted = 1;
          p++;
      }
    }
    return 1;
}

static struct mailcap *
loadMailcap(char *filename)
{
    FILE *f;
    int i, n;
    Str tmp;
    struct mailcap *mcap;

    f = fopen(expandPath(filename), "r");
    if (f == NULL)
      return NULL;
    i = 0;
    while (tmp = Strfgets(f), tmp->length > 0) {
      if (tmp->ptr[0] != '#')
          i++;
    }
    fseek(f, 0, 0);
    n = i;
    mcap = New_N(struct mailcap, n + 1);
    i = 0;
    while (tmp = Strfgets(f), tmp->length > 0) {
      if (tmp->ptr[0] == '#')
          continue;
      redo:
      while (IS_SPACE(Strlastchar(tmp)))
          Strshrink(tmp, 1);
      if (Strlastchar(tmp) == '\\') {
          /* continuation */
          Strshrink(tmp, 1);
          Strcat(tmp, Strfgets(f));
          goto redo;
      }
      if (extractMailcapEntry(tmp->ptr, &mcap[i]))
          i++;
    }
    bzero(&mcap[i], sizeof(struct mailcap));
    fclose(f);
    return mcap;
}

void
initMailcap()
{
    TextListItem *tl;
    int i;

    if (non_null(mailcap_files))
      mailcap_list = make_domain_list(mailcap_files);
    else
      mailcap_list = NULL;
    if (mailcap_list == NULL)
      return;
    UserMailcap = New_N(struct mailcap *, mailcap_list->nitem);
    for (i = 0, tl = mailcap_list->first; tl; i++, tl = tl->next)
      UserMailcap[i] = loadMailcap(tl->ptr);

}

char *
acceptableMimeTypes()
{
    static Str types = NULL;
    TextList *l;
    Hash_si *mhash;
    char *p;
    int i;

    if (types != NULL)
      return types->ptr;

    /* generate acceptable media types */
    l = newTextList();
    mhash = newHash_si(16);   /* XXX */
    pushText(l, "text");
    putHash_si(mhash, "text", 1);
    pushText(l, "image");
    putHash_si(mhash, "image", 1);
    for (i = 0; i < mailcap_list->nitem; i++) {
      struct mailcap *mp = UserMailcap[i];
      char *mt;
      if (mp == NULL)
          continue;
      for (; mp->type; mp++) {
          p = strchr(mp->type, '/');
          if (p == NULL)
            continue;
          mt = allocStr(mp->type, p - mp->type);
          if (getHash_si(mhash, mt, 0) == 0) {
            pushText(l, mt);
            putHash_si(mhash, mt, 1);
          }
      }
    }
    while ((p = popText(l)) != NULL) {
      if (types == NULL)
          types = Strnew();
      else
          Strcat_charp(types, ", ");
      Strcat_charp(types, p);
      Strcat_charp(types, "/*");
    }
    return types->ptr;
}

struct mailcap *
searchExtViewer(char *type)
{
    struct mailcap *p;
    int i;

    if (mailcap_list == NULL)
      goto no_user_mailcap;

    for (i = 0; i < mailcap_list->nitem; i++) {
      if ((p = searchMailcap(UserMailcap[i], type)) != NULL)
          return p;
    }

  no_user_mailcap:
    return searchMailcap(DefaultMailcap, type);
}

#define MC_NORMAL 0
#define MC_PREC   1
#define MC_PREC2  2
#define MC_QUOTED 3

#define MCF_SQUOTED (1 << 0)
#define MCF_DQUOTED (1 << 1)

Str
quote_mailcap(char *s, int flag)
{
    Str d;

    d = Strnew();

    for (;; ++s)
      switch (*s) {
      case '\0':
          goto end;
      case '$':
      case '`':
      case '"':
      case '\\':
          if (!(flag & MCF_SQUOTED))
            Strcat_char(d, '\\');

          Strcat_char(d, *s);
          break;
      case '\'':
          if (flag & MCF_SQUOTED) {
            Strcat_charp(d, "'\\''");
            break;
          }
      default:
          if (!flag && !IS_ALNUM(*s))
            Strcat_char(d, '\\');
      case '_':
      case '.':
      case ':':
      case '/':
          Strcat_char(d, *s);
          break;
      }
  end:
    return d;
}


static Str
unquote_mailcap_loop(char *qstr, char *type, char *name, char *attr,
                 int *mc_stat, int flag0)
{
    Str str, tmp, test, then;
    char *p;
    int status = MC_NORMAL, prev_status = MC_NORMAL, sp = 0, flag;

    if (mc_stat)
      *mc_stat = 0;

    if (qstr == NULL)
      return NULL;

    str = Strnew();
    tmp = test = then = NULL;

    for (flag = flag0, p = qstr; *p; p++) {
      if (status == MC_QUOTED) {
          if (prev_status == MC_PREC2)
            Strcat_char(tmp, *p);
          else
            Strcat_char(str, *p);
          status = prev_status;
          continue;
      }
      else if (*p == '\\') {
          prev_status = status;
          status = MC_QUOTED;
          continue;
      }
      switch (status) {
      case MC_NORMAL:
          if (*p == '%') {
            status = MC_PREC;
          }
          else {
            if (*p == '\'') {
                if (!flag0 && flag & MCF_SQUOTED)
                  flag &= ~MCF_SQUOTED;
                else if (!flag)
                  flag |= MCF_SQUOTED;
            }
            else if (*p == '"') {
                if (!flag0 && flag & MCF_DQUOTED)
                  flag &= ~MCF_DQUOTED;
                else if (!flag)
                  flag |= MCF_DQUOTED;
            }
            Strcat_char(str, *p);
          }
          break;
      case MC_PREC:
          if (IS_ALPHA(*p)) {
            switch (*p) {
            case 's':
                if (name) {
                  Strcat_charp(str, quote_mailcap(name, flag)->ptr);
                  if (mc_stat)
                      *mc_stat |= MCSTAT_REPNAME;
                }
                break;
            case 't':
                if (type) {
                  Strcat_charp(str, quote_mailcap(type, flag)->ptr);
                  if (mc_stat)
                      *mc_stat |= MCSTAT_REPTYPE;
                }
                break;
            }
            status = MC_NORMAL;
          }
          else if (*p == '{') {
            status = MC_PREC2;
            test = then = NULL;
            tmp = Strnew();
          }
          else if (*p == '%') {
            Strcat_char(str, *p);
          }
          break;
      case MC_PREC2:
          if (sp > 0 || *p == '{') {
            Strcat_char(tmp, *p);

            switch (*p) {
            case '{':
                ++sp;
                break;
            case '}':
                --sp;
                break;
            default:
                break;
            }
          }
          else if (*p == '}') {
            char *q;
            if (attr && (q = strcasestr(attr, tmp->ptr)) != NULL &&
                (q == attr || IS_SPACE(*(q - 1)) || *(q - 1) == ';') &&
                matchattr(q, tmp->ptr, tmp->length, &tmp)) {
                Strcat_charp(str, quote_mailcap(tmp->ptr, flag)->ptr);
                if (mc_stat)
                  *mc_stat |= MCSTAT_REPPARAM;
            }
            status = MC_NORMAL;
          }
          else {
            Strcat_char(tmp, *p);
          }
          break;
      }
    }
    return str;
}

Str
unquote_mailcap(char *qstr, char *type, char *name, char *attr, int *mc_stat)
{
    return unquote_mailcap_loop(qstr, type, name, attr, mc_stat, 0);
}

Generated by  Doxygen 1.6.0   Back to index