~ubuntu-branches/debian/squeeze/alpine/squeeze

« back to all changes in this revision

Viewing changes to pith/mimetype.c

  • Committer: Bazaar Package Importer
  • Author(s): Asheesh Laroia
  • Date: 2007-02-17 13:17:42 UTC
  • Revision ID: james.westby@ubuntu.com-20070217131742-99x5c6cpg1pbkdhw
Tags: upstream-0.82+dfsg
ImportĀ upstreamĀ versionĀ 0.82+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if !defined(lint) && !defined(DOS)
 
2
static char rcsid[] = "$Id: mimetype.c 343 2006-12-22 18:25:39Z hubert@u.washington.edu $";
 
3
#endif
 
4
 
 
5
/*
 
6
 * ========================================================================
 
7
 * Copyright 2006 University of Washington
 
8
 *
 
9
 * Licensed under the Apache License, Version 2.0 (the "License");
 
10
 * you may not use this file except in compliance with the License.
 
11
 * You may obtain a copy of the License at
 
12
 *
 
13
 *     http://www.apache.org/licenses/LICENSE-2.0
 
14
 *
 
15
 * ========================================================================
 
16
 */
 
17
 
 
18
#include "../pith/headers.h"
 
19
#include "../pith/mimetype.h"
 
20
#include "../pith/state.h"
 
21
#include "../pith/conf.h"
 
22
#include "../pith/mailcap.h"
 
23
#include "../pith/util.h"
 
24
 
 
25
/*
 
26
 * We've decided not to implement the RFC1524 standard minimum path, because
 
27
 * some of us think it is harder to debug a problem when you may be misled
 
28
 * into looking at the wrong mailcap entry.  Likewise for MIME.Types files.
 
29
 */
 
30
#if defined(DOS) || defined(OS2)
 
31
#define MT_PATH_SEPARATOR ';'
 
32
#define MT_USER_FILE      "MIMETYPE"
 
33
#define MT_STDPATH        NULL
 
34
#else /* !DOS */
 
35
#define MT_PATH_SEPARATOR ':'
 
36
#define MT_USER_FILE      NULL
 
37
#define MT_STDPATH         \
 
38
                ".mime.types:/etc/mime.types:/usr/local/lib/mime.types"
 
39
#endif /* !DOS */
 
40
 
 
41
#define LINE_BUF_SIZE      2000
 
42
 
 
43
 
 
44
/*
 
45
 * Types used to pass parameters and operator functions to the
 
46
 * mime.types searching routines.
 
47
 */
 
48
#define MT_MAX_FILE_EXTENSION 3
 
49
 
 
50
typedef int (* MT_OPERATORPROC)(MT_MAP_T *, FILE *);
 
51
 
 
52
 
 
53
/*
 
54
 * Internal prototypes
 
55
 */
 
56
int  mt_get_file_ext(char *, char **);
 
57
int  mt_srch_mime_type(MT_OPERATORPROC, MT_MAP_T *);
 
58
int  mt_browse_types_file(MT_OPERATORPROC, MT_MAP_T *, char *);
 
59
int  mt_srch_by_type(MT_MAP_T *, FILE *);
 
60
int  mt_translate_type(char *);
 
61
 
 
62
 
 
63
 
 
64
/*
 
65
 * Exported function that does the work of sniffing the mime.types
 
66
 * files and filling in the body pointer if found.  Returns 1 (TRUE) if
 
67
 * extension found, and body pointer filled in, 0 (FALSE) otherwise.
 
68
 */
 
69
int
 
70
set_mime_type_by_extension(struct mail_bodystruct *body, char *filename)
 
71
{
 
72
    MT_MAP_T  e2b;
 
73
 
 
74
    if(mt_get_file_ext(filename, &e2b.from.ext)
 
75
       && mt_srch_mime_type(mt_srch_by_ext, &e2b)){
 
76
        body->type    = e2b.to.mime.type;
 
77
        body->subtype = e2b.to.mime.subtype; /* NOTE: subtype was malloc'd */
 
78
        return(1);
 
79
    }
 
80
 
 
81
    return(0);
 
82
}
 
83
 
 
84
 
 
85
/*
 
86
 * Exported function that maps from mime types to file extensions.
 
87
 */
 
88
int
 
89
set_mime_extension_by_type (char *ext, char *mtype)
 
90
{
 
91
    MT_MAP_T t2e;
 
92
 
 
93
    t2e.from.mime_type = mtype;
 
94
    t2e.to.ext         = ext;
 
95
    return (mt_srch_mime_type (mt_srch_by_type, &t2e));
 
96
}
 
97
    
 
98
 
 
99
 
 
100
 
 
101
/* 
 
102
 * Separate and return a pointer to the first character in the 'filename'
 
103
 * character buffer that comes after the rightmost '.' character in the
 
104
 * filename. (What I mean is a pointer to the filename - extension).
 
105
 *
 
106
 * Returns 1 if an extension is found, 0 otherwise.
 
107
 */
 
108
int
 
109
mt_get_file_ext(char *filename, char **extension)
 
110
{
 
111
    dprint((5, "mt_get_file_ext : filename=\"%s\", ",
 
112
           filename ? filename : "?"));
 
113
 
 
114
    for(*extension = NULL; filename && *filename; filename++)
 
115
      if(*filename == '.')
 
116
        *extension = filename + 1;
 
117
 
 
118
    dprint((5, "extension=\"%s\"\n",
 
119
           (extension && *extension) ? *extension : "?"));
 
120
 
 
121
    return(*extension ? 1 : 0);
 
122
}
 
123
 
 
124
 
 
125
/*
 
126
 * Build a list of possible mime.type files.  For each one that exists
 
127
 * call the mt_operator function.
 
128
 * Loop terminates when mt_operator returns non-zero.  
 
129
 */
 
130
int
 
131
mt_srch_mime_type(MT_OPERATORPROC mt_operator, MT_MAP_T *mt_map)
 
132
{
 
133
    char *s, *pathcopy, *path;
 
134
    int   rv = 0;
 
135
  
 
136
    dprint((5, "- mt_srch_mime_type -\n"));
 
137
 
 
138
    pathcopy = mc_conf_path(ps_global->VAR_MIMETYPE_PATH, getenv("MIMETYPES"),
 
139
                            MT_USER_FILE, MT_PATH_SEPARATOR, MT_STDPATH);
 
140
 
 
141
    path = pathcopy;                    /* overloaded "path" */
 
142
 
 
143
    dprint((7, "mime_types: path: %s\n", path ? path : "?"));
 
144
    while(path){
 
145
        if(s = strindex(path, MT_PATH_SEPARATOR))
 
146
          *s++ = '\0';
 
147
 
 
148
        if(rv = mt_browse_types_file(mt_operator, mt_map, path))
 
149
          break;
 
150
 
 
151
        path = s;
 
152
    }
 
153
  
 
154
    if(pathcopy)
 
155
      fs_give((void **)&pathcopy);
 
156
 
 
157
    if(!rv && mime_os_specific_access()){
 
158
        if(mt_operator == mt_srch_by_ext){
 
159
            char buf[256];
 
160
 
 
161
            if(mime_get_os_mimetype_from_ext(mt_map->from.ext, buf, 256)){
 
162
                if(s = strindex(buf, '/')){
 
163
                    *s++ = '\0';
 
164
                    mt_map->to.mime.type = mt_translate_type(buf);
 
165
                    mt_map->to.mime.subtype = cpystr(s);
 
166
                    rv = 1;
 
167
                }
 
168
            }
 
169
        }
 
170
        else if(mt_operator == mt_srch_by_type){
 
171
            if(mime_get_os_ext_from_mimetype(mt_map->from.mime_type,
 
172
                                  mt_map->to.ext, 32)){
 
173
                /* the 32 comes from var ext[] in display_attachment() */
 
174
                if(*(s = mt_map->to.ext) == '.')
 
175
                  while(*s = *(s+1))
 
176
                    s++;
 
177
 
 
178
                rv = 1;
 
179
            }
 
180
        }
 
181
        else
 
182
          panic("Unhandled mime type search");
 
183
    }
 
184
 
 
185
 
 
186
    return(rv);
 
187
}
 
188
 
 
189
 
 
190
/*
 
191
 * Try to match a file extension against extensions found in the file
 
192
 * ``filename'' if that file exists. return 1 if a match
 
193
 * was found and 0 in all other cases.
 
194
 */
 
195
int
 
196
mt_browse_types_file(MT_OPERATORPROC mt_operator, MT_MAP_T *mt_map, char *filename)
 
197
{
 
198
    int   rv = 0;
 
199
    FILE *file;
 
200
 
 
201
    if(file = our_fopen(filename, "rb")){
 
202
        rv = (*mt_operator)(mt_map, file);
 
203
        fclose(file);
 
204
    }
 
205
    else
 
206
      dprint((1, "mt_browse: FAILED open(%s) : %s.\n",
 
207
                 filename ? filename : "?", error_description(errno)));
 
208
 
 
209
    return(rv);
 
210
}
 
211
 
 
212
 
 
213
/*
 
214
 * scan each line of the file. Treat each line as a mime type definition.
 
215
 * The first word is a type/subtype specification. All following words
 
216
 * are file extensions belonging to that type/subtype. Words are separated
 
217
 * bij whitespace characters.
 
218
 * If a file extension occurs more than once, then the first definition
 
219
 * determines the file type and subtype.
 
220
 */
 
221
int
 
222
mt_srch_by_ext(MT_MAP_T *e2b, FILE *file)
 
223
{
 
224
    char buffer[LINE_BUF_SIZE];
 
225
#if     defined(DOS) || defined(OS2)
 
226
#define STRCMP  strucmp
 
227
#else
 
228
#define STRCMP  strcmp
 
229
#endif
 
230
 
 
231
    /* construct a loop reading the file line by line. Then check each
 
232
     * line for a matching definition.
 
233
     */
 
234
    while(fgets(buffer,LINE_BUF_SIZE,file) != NULL){
 
235
        char *typespec;
 
236
        char *try_extension;
 
237
 
 
238
        if(buffer[0] == '#')
 
239
          continue;             /* comment */
 
240
 
 
241
        /* remove last character from the buffer */
 
242
        buffer[strlen(buffer)-1] = '\0';
 
243
        /* divide the input buffer into words separated by whitespace.
 
244
         * The first words is the type and subtype. All following words
 
245
         * are file extensions.
 
246
         */
 
247
        dprint((5, "traverse: buffer=\"%s\"\n", buffer));
 
248
        typespec = strtok(buffer," \t");        /* extract type,subtype  */
 
249
        if(!typespec)
 
250
          continue;
 
251
 
 
252
        dprint((5, "typespec=\"%s\"\n", typespec ? typespec : "?"));
 
253
        while((try_extension = strtok(NULL, " \t")) != NULL){
 
254
            /* compare the extensions, and assign the type if a match
 
255
             * is found.
 
256
             */
 
257
            dprint((5,"traverse: trying ext \"%s\"\n",try_extension));
 
258
            if(STRCMP(try_extension, e2b->from.ext) == 0){
 
259
                /* split the 'type/subtype' specification */
 
260
                char *type, *subtype = NULL;
 
261
 
 
262
                type = strtok(typespec,"/");
 
263
                if(type)
 
264
                  subtype = strtok(NULL,"/");
 
265
 
 
266
                dprint((5, "traverse: type=%s, subtype=%s.\n",
 
267
                           type ? type : "<null>",
 
268
                           subtype ? subtype : "<null>"));
 
269
                /* The type is encoded as a small integer. we have to
 
270
                 * translate the character string naming the type into
 
271
                 * the corresponding number.
 
272
                 */
 
273
                e2b->to.mime.type    = mt_translate_type(type);
 
274
                e2b->to.mime.subtype = cpystr(subtype ? subtype : "x-unknown");
 
275
                return 1; /* a match has been found */
 
276
            }
 
277
        }
 
278
    }
 
279
 
 
280
    dprint((5, "traverse: search failed.\n"));
 
281
    return 0;
 
282
}
 
283
 
 
284
 
 
285
/*
 
286
 * scan each line of the file. Treat each line as a mime type definition.
 
287
 * Here we are looking for a matching type.  When that is found return the
 
288
 * first extension that is three chars or less.
 
289
 */
 
290
int
 
291
mt_srch_by_type(MT_MAP_T *t2e, FILE *file)
 
292
{
 
293
    char buffer[LINE_BUF_SIZE];
 
294
 
 
295
    /* construct a loop reading the file line by line. Then check each
 
296
     * line for a matching definition.
 
297
     */
 
298
    while(fgets(buffer,LINE_BUF_SIZE,file) != NULL){
 
299
        char *typespec;
 
300
        char *try_extension;
 
301
 
 
302
        if(buffer[0] == '#')
 
303
          continue;             /* comment */
 
304
 
 
305
        /* remove last character from the buffer */
 
306
        buffer[strlen(buffer)-1] = '\0';
 
307
        /* divide the input buffer into words separated by whitespace.
 
308
         * The first words is the type and subtype. All following words
 
309
         * are file extensions.
 
310
         */
 
311
        dprint((5, "traverse: buffer=%s.\n", buffer));
 
312
        typespec = strtok(buffer," \t");        /* extract type,subtype  */
 
313
        dprint((5, "typespec=%s.\n", typespec ? typespec : "?"));
 
314
        if (strucmp (typespec, t2e->from.mime_type) == 0) {
 
315
            while((try_extension = strtok(NULL, " \t")) != NULL) {
 
316
                if (strlen (try_extension) <= MT_MAX_FILE_EXTENSION) {
 
317
                    strncpy (t2e->to.ext, try_extension, 32);
 
318
                    /*
 
319
                     * not sure of the 32, so don't write to byte 32
 
320
                     * on purpose with
 
321
                     *     t2e->to.ext[31] = '\0';
 
322
                     * in case that breaks something
 
323
                     */
 
324
 
 
325
                    return (1);
 
326
                }
 
327
            }
 
328
        }
 
329
    }
 
330
 
 
331
    dprint((5, "traverse: search failed.\n"));
 
332
    return 0;
 
333
}
 
334
 
 
335
 
 
336
/*
 
337
 * Translate a character string representing a content type into a short 
 
338
 * integer number, according to the coding described in c-client/mail.h
 
339
 * List of content types taken from rfc1521, September 1993.
 
340
 */
 
341
int
 
342
mt_translate_type(char *type)
 
343
{
 
344
    int i;
 
345
 
 
346
    for (i=0;(i<=TYPEMAX) && body_types[i] && strucmp(type,body_types[i]);i++)
 
347
      ;
 
348
 
 
349
    if (i > TYPEMAX)
 
350
      i = TYPEOTHER;
 
351
    else if (!body_types[i])    /* if empty slot, assign it to this type */
 
352
      body_types[i] = cpystr (type);
 
353
 
 
354
    return(i);
 
355
}