Code coverage report for node-mhtml/lib/extract.js

Statements: 96.59% (85 / 88)      Branches: 89.47% (34 / 38)      Functions: 100% (15 / 15)      Lines: 100% (82 / 82)     

All files » node-mhtml/lib/ » extract.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 1511   1 1 1 1   1 1 1   1   1 1   1   1 9 9 9 9     1       9 9 9   9 9 9   9 9   9   32503   32503 32503 8   32503 8       32503 62 62 62     32503     274 54 54 54   220 220 158 158 158 9           32503 32055     32503       9 9 8               8 8   8   8   8   8   54 54   54 5 5     49 49 49 49 49 49 49               8 1   7         9 9 9 8 8           1 9    
'use strict';
 
var fs = require('fs');
var path = require('path');
var readline = require('readline');
var stream = require('stream');
 
var mkdir = require('mkdirp');
var rmdir = require('rimraf');
var mimelib = require('mimelib');
 
var EOL = require('os').EOL;
 
var Part = require(__dirname + '/part');
var PartCollection = require(__dirname + '/partCollection');
 
module.exports = extractMHTML;
 
function MHTMLExtractor(source, opts) {
  this.boundary = null;
  this.source = source;
  this.parts = new PartCollection();
  return this;
}
 
MHTMLExtractor.prototype = {
 
  getParts: function (cb) {
 
    var instream = fs.createReadStream(this.source);
    var outstream = new stream;
    var rl = readline.createInterface(instream, outstream);
 
    var lineno = 0;
    var validMhtml = false;
    var boundary, part, meta, parsed;
 
    var readMeta = false;
    var readContent = false;
 
    rl.on('line', function readLine(line) {
 
      boundary = line.match(/boundary=["'](.+?)["']/);
 
      Eif (!this.boundry) {
        if (boundary) {
          this.boundary = boundary[1];
        }
        if (line.match('Content-Type: multipart/related')) {
          validMhtml = true;
        }
      }
 
      if (line.match(new RegExp('^--' + this.boundary))) {
        readMeta = true;
        readContent = false;
        part = new Part();
      }
 
      if (readMeta === true) {
 
        // a newline after the meta block signifies the start of the content block
        if (line.match(/^$/)) {
          readMeta = false;
          readContent = true;
          this.parts.push(part);
        } else {
          meta = line.match(/^(Content-[A-Za-z-]+):(?:\s+)?(.*)/i);
          if (meta) {
            parsed = mimelib.parseHeaderLine(meta[2]);
            part.meta(meta[1], parsed.defaultValue);
            if (parsed.charset) {
              part.meta('charset', parsed.charset.replace(/["']/g, ''));
            }
          }
        }
      }
 
      if (readContent === true && !line.match(/^$/)) {
        part.content += line + EOL;
      }
 
      lineno++;
 
    }.bind(this));
 
    rl.on('close', function endRead() {
      if (!validMhtml) cb(new Error('Invalid MHTML file'));
      else cb(null);
    }.bind(this));
  },
 
  extractParts: function (dest, cb, force) {
 
    // TODO: allow mode to be passed as an argument
 
    var noParts = this.parts.length;
    var done = 0;
 
    var extract = function (err) {
 
      mkdir(dest, function (err) {
 
        Iif (err) return cb(err);
 
        this.parts.each(function (part) {
 
          var filePath = path.join(dest, part.filePath());
          var fileDir = path.dirname(filePath);
 
          if (!part.isLocal()) {
            done++;
            return;
          }
 
          part.decoded(function (err, content) {
            mkdir(fileDir, function (err) {
              Iif (err) return cb(err);
              fs.writeFile(filePath, content, function (err) {
                Iif (err) return cb(err);
                done++;
                if (done == noParts) return cb(null);
              });
            });
          });
        });
      }.bind(this));
    }.bind(this);
 
    if (force) {
      rmdir(dest, extract);
    } else {
      extract();
    }
  },
 
  extract: function (dest, cb, force) {
    var force = (typeof force === 'undefined') ? false : force;
    this.getParts(function readFile(err) {
      if (err) return cb(err);
      this.extractParts(dest, function extractParts(err) {
        cb(err);
      }, force);
    }.bind(this));
  }
};
 
function extractMHTML(source, destination, cb, force) {
  new MHTMLExtractor(source).extract(destination, cb, force);
}