Switch to unified view

a/src/internfile/mh_mail.cpp b/src/internfile/mh_mail.cpp
1
#ifndef lint
1
#ifndef lint
2
static char rcsid[] = "@(#$Id: mh_mail.cpp,v 1.14 2006-04-07 08:51:15 dockes Exp $ (C) 2005 J.F.Dockes";
2
static char rcsid[] = "@(#$Id: mh_mail.cpp,v 1.15 2006-09-05 08:05:02 dockes Exp $ (C) 2005 J.F.Dockes";
3
#endif
3
#endif
4
/*
4
/*
5
 *   This program is free software; you can redistribute it and/or modify
5
 *   This program is free software; you can redistribute it and/or modify
6
 *   it under the terms of the GNU General Public License as published by
6
 *   it under the terms of the GNU General Public License as published by
7
 *   the Free Software Foundation; either version 2 of the License, or
7
 *   the Free Software Foundation; either version 2 of the License, or
...
...
45
45
46
#ifndef NO_NAMESPACES
46
#ifndef NO_NAMESPACES
47
using namespace std;
47
using namespace std;
48
#endif /* NO_NAMESPACES */
48
#endif /* NO_NAMESPACES */
49
49
50
static void 
51
walkmime(RclConfig *cnf, string &out, Binc::MimePart& doc, int depth);
52
53
MimeHandlerMail::~MimeHandlerMail()
50
MimeHandlerMail::~MimeHandlerMail()
54
{
51
{
55
    if (m_vfp) {
52
    if (m_vfp) {
56
    fclose((FILE *)m_vfp);
53
    fclose((FILE *)m_vfp);
57
    m_vfp = 0;
54
    m_vfp = 0;
...
...
239
    if (doc.h.getFirstHeader("Subject", hi)) {
236
    if (doc.h.getFirstHeader("Subject", hi)) {
240
    rfc2047_decode(hi.getValue(), transcoded);
237
    rfc2047_decode(hi.getValue(), transcoded);
241
    docout.text += string("Subject: ") + transcoded + string("\n");
238
    docout.text += string("Subject: ") + transcoded + string("\n");
242
    }
239
    }
243
240
244
    LOGDEB2(("MimeHandlerMail::processone: ismultipart %d mime subtype '%s'\n",
241
    LOGDEB2(("MimeHandlerMail::processone:ismultipart %d mime subtype '%s'\n",
245
        doc.isMultipart(), doc.getSubType().c_str()));
242
        doc.isMultipart(), doc.getSubType().c_str()));
246
    walkmime(m_conf, docout.text, doc, 0);
243
    walkmime(docout.text, doc, 0);
247
244
248
    // LOGDEB(("MimeHandlerMail::processone: text: '%s'\n", docout.text.c_str()));
245
    LOGDEB2(("MimeHandlerMail::processone:text:[%s]\n", docout.text.c_str()));
249
    return MimeHandler::MHDone;
246
    return MimeHandler::MHDone;
250
}
247
}
251
248
252
// Recursively walk the message mime parts and concatenate all the
249
// Recursively walk the message mime parts and concatenate all the
253
// inline html or text that we find anywhere.
250
// inline html or text that we find anywhere.
254
static void walkmime(RclConfig *cnf, string &out, Binc::MimePart& doc, 
251
void MimeHandlerMail::walkmime(string &out, Binc::MimePart& doc, int depth)
255
           int depth)
256
{
252
{
257
    if (depth > 5) {
253
    if (depth > 5) {
258
    LOGINFO(("walkmime: max depth exceeded\n"));
254
    LOGINFO(("walkmime: max depth exceeded\n"));
259
    return;
255
    return;
260
    }
256
    }
...
...
267
    // process it For mixed and related, we process each part.
263
    // process it For mixed and related, we process each part.
268
    std::vector<Binc::MimePart>::iterator it;
264
    std::vector<Binc::MimePart>::iterator it;
269
    if (!stringicmp("mixed", doc.getSubType()) || 
265
    if (!stringicmp("mixed", doc.getSubType()) || 
270
        !stringicmp("related", doc.getSubType())) {
266
        !stringicmp("related", doc.getSubType())) {
271
        for (it = doc.members.begin(); it != doc.members.end();it++) {
267
        for (it = doc.members.begin(); it != doc.members.end();it++) {
272
        walkmime(cnf, out, *it, depth+1);
268
        walkmime(out, *it, depth+1);
273
        }
269
        }
274
    } else if (!stringicmp("alternative", doc.getSubType())) {
270
    } else if (!stringicmp("alternative", doc.getSubType())) {
275
        std::vector<Binc::MimePart>::iterator ittxt, ithtml;
271
        std::vector<Binc::MimePart>::iterator ittxt, ithtml;
276
        ittxt = ithtml = doc.members.end();
272
        ittxt = ithtml = doc.members.end();
277
        int i = 1;
273
        int i = 1;
...
...
290
        else if (!stringlowercmp("text/html", content_type.value)) 
286
        else if (!stringlowercmp("text/html", content_type.value)) 
291
            ithtml = it;
287
            ithtml = it;
292
        }
288
        }
293
        if (ittxt != doc.members.end()) {
289
        if (ittxt != doc.members.end()) {
294
        LOGDEB2(("walkmime: alternative: chose text/plain part\n"))
290
        LOGDEB2(("walkmime: alternative: chose text/plain part\n"))
295
        walkmime(cnf, out, *ittxt, depth+1);
291
        walkmime(out, *ittxt, depth+1);
296
        } else if (ithtml != doc.members.end()) {
292
        } else if (ithtml != doc.members.end()) {
297
        LOGDEB2(("walkmime: alternative: chose text/html part\n"))
293
        LOGDEB2(("walkmime: alternative: chose text/html part\n"))
298
        walkmime(cnf, out, *ithtml, depth+1);
294
        walkmime(out, *ithtml, depth+1);
299
        }
295
        }
300
    }
296
    }
301
    } else {
297
    } else {
302
  // If content-type is text or html and content-disposition is inline, 
298
  // "Simple" part. See what it is:
303
  // decode and add to text.
304
299
305
    // Get and parse content-type header.
300
    // Get and parse content-type header.
306
    Binc::HeaderItem hi;
301
    Binc::HeaderItem hi;
307
    string ctt = "text/plain";
302
    string ctt = "text/plain";
308
    if (doc.h.getFirstHeader("Content-Type", hi)) {
303
    if (doc.h.getFirstHeader("Content-Type", hi)) {
309
        ctt = hi.getValue();
304
        ctt = hi.getValue();
310
    }
305
    }
311
    LOGDEB2(("walkmime:content-type: %s\n", ctt.c_str()));
306
    LOGDEB2(("walkmime:content-type: %s\n", ctt.c_str()));
312
    MimeHeaderValue content_type;
307
    MimeHeaderValue content_type;
313
    parseMimeHeaderValue(ctt, content_type);
308
    parseMimeHeaderValue(ctt, content_type);
309
      
310
  // Get and parse Content-Disposition header
311
  string ctd = "inline";
312
  if (doc.h.getFirstHeader("Content-Disposition", hi)) {
313
      ctd = hi.getValue();
314
  }
315
  MimeHeaderValue content_disposition;
316
  parseMimeHeaderValue(ctd, content_disposition);
317
318
  LOGDEB2(("Content_disposition:[%s]\n", 
319
      content_disposition.value.c_str()));
320
321
  // If this is an attachment, we index the file name if any and, when
322
  // previewing, at least show that it was there.
323
  if (!stringlowercmp("attachment", content_disposition.value)) {
324
      string rafn = "NoFileName", afn;
325
      map<string,string>::const_iterator it;
326
      it = content_disposition.params.find(string("filename"));
327
      if (it != content_type.params.end())
328
      rafn = it->second;
329
      rfc2047_decode(rafn, afn);
330
      out += "\n";
331
      if (m_forPreview)
332
      out += "[Attachment: ";
333
      out += afn;
334
      if (m_forPreview)
335
      out += "]";
336
      out += "\n\n";
337
      // Attachment: we're done with this part
338
      return;
339
  }
340
341
  // The only other disposition that interests us is "inline", and then
342
  // this has to be plain text or html
343
  if (stringlowercmp("inline", content_disposition.value)) {
344
      return;
345
  }
314
    if (stringlowercmp("text/plain", content_type.value) && 
346
    if (stringlowercmp("text/plain", content_type.value) && 
315
        stringlowercmp("text/html", content_type.value)) {
347
        stringlowercmp("text/html", content_type.value)) {
316
        return;
348
        return;
317
    }
349
    }
318
350
...
...
332
        !stringlowercmp("x-user-defined", charset) || 
364
        !stringlowercmp("x-user-defined", charset) || 
333
        !stringlowercmp("x-unknown", charset) || 
365
        !stringlowercmp("x-unknown", charset) || 
334
        !stringlowercmp("unknown", charset) ) {
366
        !stringlowercmp("unknown", charset) ) {
335
        charset = "iso-8859-1";
367
        charset = "iso-8859-1";
336
    }
368
    }
337
      
338
  // Content disposition
339
  string ctd = "inline";
340
  if (doc.h.getFirstHeader("Content-Disposition", hi)) {
341
      ctd = hi.getValue();
342
  }
343
  MimeHeaderValue content_disposition;
344
  parseMimeHeaderValue(ctd, content_disposition);
345
  if (stringlowercmp("inline", content_disposition.value)) {
346
      return;
347
  }
348
369
349
    // Content transfer encoding
370
    // Content transfer encoding
350
    string cte = "7bit";
371
    string cte = "7bit";
351
    if (doc.h.getFirstHeader("Content-Transfer-Encoding", hi)) {
372
    if (doc.h.getFirstHeader("Content-Transfer-Encoding", hi)) {
352
        cte = hi.getValue();
373
        cte = hi.getValue();
...
...
355
    LOGDEB2(("walkmime: final: body start offset %d, length %d\n", 
376
    LOGDEB2(("walkmime: final: body start offset %d, length %d\n", 
356
         doc.getBodyStartOffset(), doc.getBodyLength()));
377
         doc.getBodyStartOffset(), doc.getBodyLength()));
357
    string body;
378
    string body;
358
    doc.getBody(body, 0, doc.bodylength);
379
    doc.getBody(body, 0, doc.bodylength);
359
380
360
    // Decode content transfer encoding
381
    // Decode according to content transfer encoding
361
    if (!stringlowercmp("quoted-printable", cte)) {
382
    if (!stringlowercmp("quoted-printable", cte)) {
362
        string decoded;
383
        string decoded;
363
        if (!qp_decode(body, decoded)) {
384
        if (!qp_decode(body, decoded)) {
364
        LOGERR(("walkmime: quoted-printable decoding failed !\n"));
385
        LOGERR(("walkmime: quoted-printable decoding failed !\n"));
365
        return;
386
        return;
...
...
379
        return;
400
        return;
380
        }
401
        }
381
        body = decoded;
402
        body = decoded;
382
    }
403
    }
383
404
384
  string transcoded;
405
  // Handle html stripping and transcoding to utf8
406
  string utf8;
385
    if (!stringlowercmp("text/html", content_type.value)) {
407
    if (!stringlowercmp("text/html", content_type.value)) {
386
        MimeHandlerHtml mh;
408
        MimeHandlerHtml mh;
387
        Rcl::Doc hdoc;
409
        Rcl::Doc hdoc;
388
        mh.charsethint = charset;
410
        mh.charsethint = charset;
389
        mh.mkDoc(cnf, "", body, content_type.value,  hdoc);
411
        mh.mkDoc(m_conf, "", body, content_type.value,  hdoc);
390
        transcoded = hdoc.text;
412
        utf8 = hdoc.text;
391
    } else {
413
    } else {
392
        // Transcode to utf-8 
414
        // Transcode to utf-8 
393
        if (!transcode(body, transcoded, charset, "UTF-8")) {
415
        if (!transcode(body, utf8, charset, "UTF-8")) {
394
        LOGERR(("walkmime: transcode failed from cs '%s' to UTF-8\n",
416
        LOGERR(("walkmime: transcode failed from cs '%s' to UTF-8\n",
395
            charset.c_str()));
417
            charset.c_str()));
396
      transcoded = body;
418
      utf8 = body;
397
        }
419
        }
398
    }
420
    }
399
421
400
    out += string("\r\n") + transcoded;
422
    out += string("\r\n") + utf8;
401
    LOGDEB2(("walkmime: out now: [%s]\n", out.c_str()));
423
    LOGDEB2(("walkmime: out now: [%s]\n", out.c_str()));
402
    }
424
    }
403
}
425
}