Beispiel #1
0
static void
MimeContainer_finalize (MimeObject *object)
{
  MimeContainer *cont = (MimeContainer *) object;

  /* Do this first so that children have their parse_eof methods called
   in forward order (0-N) but are destroyed in backward order (N-0)
   */
  if (!object->closed_p)
  object->clazz->parse_eof (object, false);
  if (!object->parsed_p)
  object->clazz->parse_end (object, false);

  if (cont->children)
  {
    int i;
    for (i = cont->nchildren-1; i >= 0; i--)
    {
      MimeObject *kid = cont->children[i];
      if (kid)
      mime_free(kid);
      cont->children[i] = 0;
    }
    PR_FREEIF(cont->children);
    cont->nchildren = 0;
  }
  ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
}
Beispiel #2
0
/*
 * Get the mime ebXML message
 */
MIME *ebxml_getmessage (XML *xml, QUEUEROW *r)
{
  MIME *msg, *payload, *soap;
  char *pid,
       *organization,
       buf[MAX_PATH];
  int route;

  if ((route = cfg_route_index (xml, queue_field_get (r, "ROUTEINFO"))) 
    < 0) return (NULL);
  organization = cfg_org (xml);
  pid = queue_field_get (r, "MESSAGEID");
  if (pid != NULL)
    pid = strchr (pid, '-');
  if (pid++ == NULL)
  {
    error ("Can't get PID from MESSAGEID\n");
    return (NULL);
  }
  if (strcmp (queue_field_get (r, "ACTION"), "Ping"))
  {
    if ((payload = ebxml_getpayload (xml, r)) == NULL)
      return (NULL);
  }
  else
    payload = NULL;
  if ((soap = ebxml_getsoap (xml, r)) == NULL)
  {
    mime_free (payload);
    return (NULL);
  }
  debug ("building multipart mime message\n");
  msg = mime_alloc ();
  sprintf (buf, "type=\"text/xml\"; start=\"ebxml-envelope@%s\";",
     organization);
  mime_setBoundary (msg, buf);
  sprintf (buf, "%s:%s",
    cfg_route (xml, route, "Host"),
    cfg_route (xml, route, "Port"));
  mime_setHeader (msg, "Host", buf, 99);
  mime_setHeader (msg, "Connection", "Close", 99);
  if (strcmp ("basic", 
    cfg_route (xml, route, "Authentication.Type")) == 0)
  {
    basicauth_request (buf, 
      cfg_route (xml, route, "Authentication.Id"),
      cfg_route (xml, route, "Authentication.Password"));
    pid = strchr (buf, ':');
    *pid++ = 0;
    while (isspace (*pid)) pid++;
    mime_setHeader (msg, buf, pid, 99);
  }
  mime_setHeader (msg, "SOAPAction", "\"ebXML\"", 99);
  mime_setMultiPart (msg, soap);
  if (payload != NULL)
    mime_setMultiPart (msg, payload);
  debug ("Completed multipart soap message\n");
  return (msg);
}
Beispiel #3
0
int main (int argc, char **argv)
{
  XML *xml;
  QUEUE *q;
  QUEUEROW *r;
  MIME *m;
  char *ch;
  int arg = 1;

  xml = xml_parse (PhineasConfig);
  loadpath (cfg_installdir (xml));
  queue_init (xml);

  /* test folder polling */
  if ((argc > arg) && (strcmp (argv[arg], "-f") == 0))
  {
    fpoller_register ("ebxml", ebxml_fprocessor);
    fpoller_task (xml);
    arg++;
    ran = 0;
  }
  /* test message from queue */
  if ((argc > arg) && (strcmp (argv[arg], "-m") == 0))
  {
    if ((q = queue_find ("MemSendQ")) == NULL)
      error ("can't find MemSendQ");
    else if ((r = queue_pop (q)) == NULL)
      error ("can't pop row\n");
    /*
    else if ((m = ebxml_getsoap (xml, r)) == NULL)
      error ("can't get soap container\n");
    */
    else if ((m = ebxml_getmessage (xml, r)) == NULL)
      error ("can't get message\n");
    else if ((ch = mime_format (m)) == NULL)
      error ("Can't format soap containter\n");
    else
      debug ("message MIME\n%s\n", ch);
    free (ch);
    mime_free (m);
    queue_row_free (r);
    arg++;
  }
  /* test queue polling */
  if ((argc > arg) && (strcmp (argv[arg], "-q") == 0))
  {
    qpoller_register ("EbXmlSndQ", ebxml_qprocessor);
    qpoller_task (xml);
    arg++;
    ran = 0;
  }
  queue_shutdown ();
  xml_free (xml);
  info ("%s %s\n", argv[0], Errors ? "failed" : "passed");
  exit (Errors);
}
Beispiel #4
0
int main(int argc, char **argv)
{
	struct sigaction sig_stop;
	struct sigaction sig_time;

	_main = main_init(argc, argv);
	_log = log_init();
	_main->conf = conf_init(argc, argv);
	_main->work = work_init();

	_main->tcp = tcp_init();
	_main->node = node_init();
	_main->mime = mime_init();

	/* Check configuration */
	conf_print();

	/* Catch SIG INT */
	unix_signal(&sig_stop, &sig_time);

	/* Fork daemon */
	unix_fork(log_console(_log));

	/* Increase limits */
	unix_limits(_main->conf->cores, CONF_EPOLL_MAX_EVENTS);

	/* Load mime types */
	mime_load();
	mime_hash();

	/* Prepare TCP daemon */
	tcp_start();

	/* Drop privileges */
	unix_dropuid0();

	/* Start worker threads */
	work_start();

	/* Stop worker threads */
	work_stop();

	/* Stop TCP daemon */
	tcp_stop();

	mime_free();
	node_free();
	tcp_free();

	work_free();
	conf_free();
	log_free(_log);
	main_free();

	return 0;
}
Beispiel #5
0
/*
 * free a mime structure including all parts of a multipart
 */
MIME *mime_free (MIME *m)
{
  if (m == NULL)
    return;
  mime_free (m->next);
  if (m->headers != NULL)
    free (m->headers);
  if (m->body != NULL)
    free (m->body);
  free (m);
  return (NULL);
}
Beispiel #6
0
static void
MimeMultipartRelated_finalize (MimeObject *obj)
{
  MimeMultipartRelated* relobj = (MimeMultipartRelated*) obj;
  PR_FREEIF(relobj->base_url);
  PR_FREEIF(relobj->curtag);
  if (relobj->buffered_hdrs) {
	PR_FREEIF(relobj->buffered_hdrs->all_headers);
	PR_FREEIF(relobj->buffered_hdrs->heads);
	PR_FREEIF(relobj->buffered_hdrs);
  }
  PR_FREEIF(relobj->head_buffer);
  relobj->head_buffer_fp = 0;
  relobj->head_buffer_size = 0;
  if (relobj->hash) {
    PL_HashTableEnumerateEntries(relobj->hash, mime_multipart_related_nukehash, NULL);
    PL_HashTableDestroy(relobj->hash);
    relobj->hash = NULL;
  }

  if (relobj->input_file_stream)
  {
    relobj->input_file_stream->Close();
    relobj->input_file_stream = nullptr;
  }

  if (relobj->output_file_stream)
  {
    relobj->output_file_stream->Close();
    relobj->output_file_stream = nullptr;
  }

  if (relobj->file_buffer)
  {
    relobj->file_buffer->Remove(false);
    relobj->file_buffer = nullptr;
  }
  
  if (relobj->headobj) {
    mime_free(relobj->headobj);
    relobj->headobj = nullptr;
  }

  ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(obj);
}
Beispiel #7
0
/*
 * A queue polling processor for ebxml queues - register this with
 * the qpoller.
 *
 * This builds an ebXML MIME message, opens a connection to a
 * receiver, sends the request, processes the response, and
 * finally updates the queue status.
 */
int ebxml_qprocessor (XML *xml, QUEUEROW *r)
{
  MIME *m;

  /*
   * build an ebXML MIME message
   */
  if ((m = ebxml_getmessage (xml, r)) == NULL)
  {
    char buf[24];
    queue_field_set (r, "MESSAGECREATIONTIME", ptime (NULL, buf));
    queue_field_set (r, "PROCESSINGSTATUS", "done");
    queue_field_set (r, "TRANSPORTSTATUS", "failed");
    queue_field_set (r, "TRANSPORTERRORCODE", "bad message");
    queue_push (r);
    return (-1);
  }
  /*
   * update the queue with message status
   */
  debug ("updating queue\n");
  queue_field_set (r, "PROCESSINGSTATUS", "waiting");
  queue_field_set (r, "TRANSPORTSTATUS", "attempted");
  queue_field_set (r, "TRANSPORTERRORCODE", "");
  queue_push (r);
  /*
   * send it to the destination
   */
  debug ("sending to destination\n");
  if (ebxml_send (xml, r, m) == 0)
    ebxml_file_ack (xml, r);
  /*
   * update the queue with status from the reply
   */
  debug ("updating reply\n");
  queue_push (r);
  /*
   * release all memory
   */
  mime_free (m);
  info ("ebXML %s:%d send completed\n", 
    r->queue->name, r->rowid);
  return (0);
}
static int MimeUntypedText_open_subpart(MimeObject *obj,
                                        MimeUntypedTextSubpartType ttype,
                                        const char *type, const char *enc,
                                        const char *name, const char *desc) {
  MimeUntypedText *uty = (MimeUntypedText *)obj;
  int status = 0;
  char *h = 0;

  if (!type || !*type || !PL_strcasecmp(type, UNKNOWN_CONTENT_TYPE))
    type = APPLICATION_OCTET_STREAM;
  if (enc && !*enc) enc = 0;
  if (desc && !*desc) desc = 0;
  if (name && !*name) name = 0;

  if (uty->open_subpart) {
    status = MimeUntypedText_close_subpart(obj);
    if (status < 0) return status;
  }
  NS_ASSERTION(!uty->open_subpart, "no open subpart");
  NS_ASSERTION(!uty->open_hdrs, "no open headers");

  /* To make one of these implicitly-typed sub-objects, we make up a fake
   header block, containing only the minimum number of MIME headers needed.
   We could do most of this (Type and Encoding) by making a null header
   block, and simply setting obj->content_type and obj->encoding; but making
   a fake header block is better for two reasons: first, it means that
   something will actually be displayed when in `Show All Headers' mode;
   and second, it's the only way to communicate the filename parameter,
   aside from adding a new slot to MimeObject (which is something to be
   avoided when possible.)
   */

  uty->open_hdrs = MimeHeaders_new();
  if (!uty->open_hdrs) return MIME_OUT_OF_MEMORY;

  uint32_t hlen = strlen(type) + (enc ? strlen(enc) : 0) +
                  (desc ? strlen(desc) : 0) + (name ? strlen(name) : 0) + 100;
  h = (char *)PR_MALLOC(hlen);
  if (!h) return MIME_OUT_OF_MEMORY;

  PL_strncpyz(h, HEADER_CONTENT_TYPE ": ", hlen);
  PL_strcatn(h, hlen, type);
  PL_strcatn(h, hlen, MSG_LINEBREAK);
  status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
  if (status < 0) goto FAIL;

  if (enc) {
    PL_strncpyz(h, HEADER_CONTENT_TRANSFER_ENCODING ": ", hlen);
    PL_strcatn(h, hlen, enc);
    PL_strcatn(h, hlen, MSG_LINEBREAK);
    status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
    if (status < 0) goto FAIL;
  }

  if (desc) {
    PL_strncpyz(h, HEADER_CONTENT_DESCRIPTION ": ", hlen);
    PL_strcatn(h, hlen, desc);
    PL_strcatn(h, hlen, MSG_LINEBREAK);
    status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
    if (status < 0) goto FAIL;
  }
  if (name) {
    PL_strncpyz(h, HEADER_CONTENT_DISPOSITION ": inline; filename=\"", hlen);
    PL_strcatn(h, hlen, name);
    PL_strcatn(h, hlen, "\"" MSG_LINEBREAK);
    status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
    if (status < 0) goto FAIL;
  }

  /* push out a blank line. */
  PL_strncpyz(h, MSG_LINEBREAK, hlen);
  status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
  if (status < 0) goto FAIL;

  /* Create a child... */
  {
    bool horrid_kludge = (obj->options && obj->options->state &&
                          obj->options->state->first_part_written_p);
    if (horrid_kludge) obj->options->state->first_part_written_p = false;

    uty->open_subpart = mime_create(type, uty->open_hdrs, obj->options);

    if (horrid_kludge) obj->options->state->first_part_written_p = true;

    if (!uty->open_subpart) {
      status = MIME_OUT_OF_MEMORY;
      goto FAIL;
    }
  }

  /* Add it to the list... */
  status =
      ((MimeContainerClass *)obj->clazz)->add_child(obj, uty->open_subpart);
  if (status < 0) {
    mime_free(uty->open_subpart);
    uty->open_subpart = 0;
    goto FAIL;
  }

  /* And start its parser going. */
  status = uty->open_subpart->clazz->parse_begin(uty->open_subpart);
  if (status < 0) {
    /* MimeContainer->finalize will take care of shutting it down now. */
    uty->open_subpart = 0;
    goto FAIL;
  }

  uty->type = ttype;

FAIL:
  PR_FREEIF(h);

  if (status < 0 && uty->open_hdrs) {
    MimeHeaders_free(uty->open_hdrs);
    uty->open_hdrs = 0;
  }

  return status;
}
Beispiel #9
0
/*
 * parse a reply message and update the queue row with status
 */
int ebxml_parse_reply (char *reply, QUEUEROW *r)
{
  MIME *msg, *part;
  XML *xml;
  char *ch, buf[PTIMESZ];

  if (ebxml_status (reply))
    return (-1);
  if ((msg = mime_parse (reply)) == NULL)
  {
    error ("Failed parsing reply message\n");
    return (-1);
  }
  /* check the ebxml envelope for ack or error */
  if ((part = mime_getMultiPart (msg, 1)) == NULL)
  {
    error ("Reply missing ebxml envelope\n");
    mime_free (msg);
    return (-1);
  }
  if ((xml = xml_parse (mime_getBody (part))) == NULL)
  {
    error ("Failed parsing ebxml envelop\n");
    mime_free (msg);
    return (-1);
  }
  strcpy (buf, xml_get_text (xml, SOAPACTION));
  if (!strcmp (buf, "MessageError"))
  {
    debug ("Error reply received!\n");
    queue_field_set (r, "PROCESSINGSTATUS", "done");
    queue_field_set (r, "TRANSPORTSTATUS", "failed");
    ch = xml_get_attribute (xml, SOAPERROR, "eb:errorCode");
    debug ("%s eb:errorCode %s\n", SOAPERROR, ch);
    queue_field_set (r, "TRANSPORTERRORCODE", ch);
    queue_field_set (r, "APPLICATIONSTATUS", "not-set");
    queue_field_set (r, "APPLICATIONERRORCODE", "none");
    ch = xml_get_text (xml, SOAPERROR);
    debug ("SOAPERROR %s\n", ch);
    queue_field_set (r, "APPLICATIONRESPONSE", ch);
    queue_field_set (r, "MESSAGERECEIVEDTIME", ptime (NULL, buf));
    xml_free (xml);
    mime_free (msg);
    return (0);
  }
  xml_free (xml);

  /* Ping reply */
  if (strcmp (queue_field_get (r, "ACTION"), "Ping") == 0)
  {
    if (strcmp (buf, "Pong"))
    {
      error ("Expected 'Pong' action but got '%s'\n", buf);
      mime_free (msg);
      return (-1);
    }
    queue_field_set (r, "APPLICATIONSTATUS", "not-set");
    queue_field_set (r, "APPLICATIONERRORCODE", "none");
    queue_field_set (r, "APPLICATIONRESPONSE", "none");
    queue_field_set (r, "MESSAGERECEIVEDTIME", ptime (NULL, buf));
  }
  else /* regular reply */
  {
    if ((part = mime_getMultiPart (msg, 2)) == NULL)
    {
      error ("Reply missing status part\n");
      mime_free (msg);
      return (-1);
    }
    debug ("Body is...\n%s\n", mime_getBody (part));
    if ((xml = xml_parse (mime_getBody (part))) == NULL)
    {
      error ("Miss formatted Reply status\n");
      mime_free (msg);
      return (-1);
    }
    queue_field_set (r, "APPLICATIONSTATUS",
      xml_get_text (xml, "response.msh_response.status"));
    queue_field_set (r, "APPLICATIONERRORCODE",
      xml_get_text (xml, "response.msh_response.error"));
    queue_field_set (r, "APPLICATIONRESPONSE",
      xml_get_text (xml, "response.msh_response.appdata"));
    queue_field_set (r, "MESSAGERECEIVEDTIME", ptime (NULL, buf));
  
    /* TODO...
    queue_field_set (r, "RESPONSEMESSAGEID", "");
    queue_field_set (r, "RESPONSEARGUMENTS", "");
    queue_field_set (r, "RESPONSELOCALFILE", "");
    queue_field_set (r, "RESPONSEFILENAME", "");
    queue_field_set (r, "RESPONSEMESSAGEORIGIN", "");
    queue_field_set (r, "RESPONSEMESSAGESIGNATURE", "");
     */
    xml_free (xml);
  }
  queue_field_set (r, "PROCESSINGSTATUS", "done");
  queue_field_set (r, "TRANSPORTSTATUS", "success");
  queue_field_set (r, "TRANSPORTERRORCODE", "none");

  mime_free (msg);
  return (0);
}
Beispiel #10
0
int html_attachment(const char *list, unsigned int y, unsigned int m, unsigned int d, unsigned int n, unsigned int a)
{
	unsigned int aday;
	char *list_file;
	off_t idx_offset;
	int fd, error, got, trunc;
	idx_msgnum_t m1, m1r;
	struct idx_message idx_msg;
	idx_off_t offset;
	idx_size_t size;
	struct buffer src, dst;
	struct mime_ctx mime;
	char *body, *bend;

	if (y < MIN_YEAR || y > MAX_YEAR ||
	    m < 1 || m > 12 ||
	    d < 1 || d > 31 ||
	    n < 1 || n > 999999)
		return html_error("Invalid date or message number");
	aday = YMD2ADAY(y - MIN_YEAR, m, d);

	list_file = concat(MAIL_SPOOL_PATH "/", list, NULL);
	if (!list_file)
		return html_error(NULL);

	fd = idx_open(list);
	if (fd < 0) {
		error = errno;
		free(list_file);
		return html_error(error == ENOENT ?
		    "No such mailing list" : (error == ESRCH ?
		    "Index needs rebuild" : NULL));
	}

	error = !idx_read_aday_ok(fd, aday, &m1, sizeof(m1));
	if (error || m1 < 1 || m1 >= MAX_MAILBOX_MESSAGES) {
		idx_close(fd);
		free(list_file);
		return html_error((error || m1 > 0) ? NULL : "No such message");
	}
	m1r = m1 + n - 2; /* both m1 and n are 1-based; m1r is 0-based */
	idx_offset = IDX2MSG(m1r);
	got = idx_read(fd, idx_offset, &idx_msg, sizeof(idx_msg));
	if (got != sizeof(idx_msg))
		error = 1;

	if (idx_close(fd) || error) {
		free(list_file);
		return html_error(got ? NULL : "No such message");
	}

	if (y - MIN_YEAR != idx_msg.y ||
	    m != idx_msg.m ||
	    d != idx_msg.d) {
		free(list_file);
		return html_error("No such message");
	}

	offset = idx_msg.offset;
	size = idx_msg.size;

	trunc = size > MAX_MESSAGE_SIZE;
	if (trunc)
		size = MAX_MESSAGE_SIZE;
	if (buffer_init(&src, size)) {
		free(list_file);
		return html_error(NULL);
	}
	fd = open(list_file, O_RDONLY);
	free(list_file);
	if (fd < 0) {
		buffer_free(&src);
		return html_error("mbox open error");
	}
	error =
	    lseek(fd, offset, SEEK_SET) != offset ||
	    read_loop(fd, src.start, size) != size;
	if (close(fd) || error || mime_init(&mime, &src)) {
		buffer_free(&src);
		return html_error("mbox read error");
	}
	if (buffer_init(&dst, size)) {
		buffer_free(&src);
		mime_free(&mime);
		return html_error(NULL);
	}

	body = NULL;
	while (src.end - src.ptr > 9 && *src.ptr != '\n') {
		switch (*src.ptr) {
		case 'C':
		case 'c':
			mime_decode_header(&mime);
			continue;
		}
		mime_skip_header(&mime);
	}
	if (src.ptr >= src.end) {
		buffer_free(&src);
		buffer_free(&dst);
		mime_free(&mime);
		return html_error(NULL);
	}
	if (*src.ptr == '\n')
		body = ++src.ptr;

	const char *error_msg = "Attachment not found";
	unsigned int attachment_count = 0;
	if (a)
	do {
		if (mime.entities->boundary) {
			body = mime_next_body_part(&mime);
			if (!body || body >= src.end)
				break;
			body = mime_next_body(&mime);
		}
		if (mime.entities->boundary || !is_attachment(&mime) || ++attachment_count != a)
			body = NULL;
		if (!body) {
			bend = mime_skip_body(&mime);
			if (!bend)
				break;
			continue;
		}

		int text = !strncasecmp(mime.entities->type, "text/", 5);
		if (text) {
			buffer_appends(&dst, "Content-Type: text/plain");
			if (mime.entities->charset && enc_allowed_charset(mime.entities->charset))
				buffer_appendf(&dst, "; charset=%s", mime.entities->charset);
			buffer_appendc(&dst, '\n');
		} else {
			buffer_appends(&dst, "Content-Type: application/octet-stream\n");
		}
		buffer_appendf(&dst, "Content-Disposition: %s; filename=\"", text ? "inline" : "attachment");
		buffer_append_filename(&dst, mime.entities->filename, text);
		buffer_appends(&dst, "\"\n");

		body = mime_decode_body(&mime, RECODE_NO, &bend);
		if (trunc && (!body || bend >= src.end)) {
			error_msg = "Attachment is truncated";
			break;
		}

		buffer_appendf(&dst, "Content-Length: %llu\n\n", (unsigned long long)(mime.dst.ptr - body));
		buffer_append(&dst, body, mime.dst.ptr - body);
		error_msg = NULL;
		break;
	} while (bend < src.end && mime.entities);

	buffer_free(&src);

	if (error_msg || mime.dst.error || dst.error) {
		mime_free(&mime);
		buffer_free(&dst);
		return html_error(error_msg);
	}

	mime_free(&mime);

	return html_send(&dst);
}
static int
MimeMultipartAlternative_display_cached_part(MimeObject *obj,
                                             MimeHeaders *hdrs,
                                             MimePartBufferData *buffer,
                                             bool do_display)
{
  int status;

  char *ct = (hdrs
        ? MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, true, false)
        : 0);
  const char *dct = (((MimeMultipartClass *) obj->clazz)->default_part_type);
  MimeObject *body;
  /** Don't pass in NULL as the content-type (this means that the
   * auto-uudecode-hack won't ever be done for subparts of a
   * multipart, but only for untyped children of message/rfc822.
   */
  const char *uct = (ct && *ct) ? ct : (dct ? dct: TEXT_PLAIN);

  // We always want to display the cached part inline.
  body = mime_create(uct, hdrs, obj->options, true);
  PR_FREEIF(ct);
  if (!body) return MIME_OUT_OF_MEMORY;
  body->output_p = do_display;

  status = ((MimeContainerClass *) obj->clazz)->add_child(obj, body);
  if (status < 0)
  {
    mime_free(body);
    return status;
  }
  /* We need to muck around with the options to prevent output when
     do_display is false. More about this below. */
  /* add_child assigns body->options from obj->options, but that's
     just a pointer so if we muck with it in the child it'll modify
     the parent as well, which we definitely don't want. Therefore we
     need to make a copy. */
  body->options = new MimeDisplayOptions;
  *body->options = *obj->options;
  /* But we have to be careful about getting into a situation where
     memory could be double-freed. All of this is a gross abstraction
     violation which could be avoided if it were possible to tell
     parse_begin what output_p should be. */
  if (body->options->part_to_load)
    body->options->part_to_load = strdup(body->options->part_to_load);
  if (body->options->default_charset)
    body->options->default_charset = strdup(body->options->default_charset);
  
  /* parse_begin resets output_p. This is quite annoying. To convince
     it that we mean business, we set output_fn to null if we don't
     want output. */
  if (! do_display)
    body->options->output_fn = nullptr;

#ifdef MIME_DRAFTS
  /* if this object is a child of a multipart/related object, the parent is
     taking care of decomposing the whole part, don't need to do it at this level.
     However, we still have to call decompose_file_init_fn and decompose_file_close_fn
     in order to set the correct content-type. But don't call MimePartBufferRead
  */
  bool multipartRelatedChild = mime_typep(obj->parent,(MimeObjectClass*)&mimeMultipartRelatedClass);
  bool decomposeFile = do_display && obj->options &&
                  obj->options->decompose_file_p &&
                  obj->options->decompose_file_init_fn &&
                  !mime_typep(body, (MimeObjectClass *) &mimeMultipartClass);

  if (decomposeFile)
  {
    status = obj->options->decompose_file_init_fn (
                        obj->options->stream_closure, hdrs);
    if (status < 0) return status;
  }
#endif /* MIME_DRAFTS */

  /* Now that we've added this new object to our list of children,
   notify emitters and start its parser going. */
  MimeMultipart_notify_emitter(body);

  status = body->clazz->parse_begin(body);
  if (status < 0) return status;
  /* Now that parse_begin is done mucking with output_p, we can put
     body->options back to what it's supposed to be. Avoids a memory
     leak. */
  delete body->options;
  body->options = obj->options;

#ifdef MIME_DRAFTS
  if (decomposeFile && !multipartRelatedChild)
    status = MimePartBufferRead (buffer,
                  obj->options->decompose_file_output_fn,
                  obj->options->stream_closure);
  else
#endif /* MIME_DRAFTS */

  status = MimePartBufferRead (buffer,
                  /* The MimeConverterOutputCallback cast is to turn the
                   `void' argument into `MimeObject'. */
                  ((MimeConverterOutputCallback) body->clazz->parse_buffer),
                  body);

  if (status < 0) return status;

  /* Done parsing. */
  status = body->clazz->parse_eof(body, false);
  if (status < 0) return status;
  status = body->clazz->parse_end(body, false);
  if (status < 0) return status;

#ifdef MIME_DRAFTS
  if (decomposeFile)
  {
    status = obj->options->decompose_file_close_fn ( obj->options->stream_closure );
    if (status < 0) return status;
  }
#endif /* MIME_DRAFTS */

  return 0;
}
Beispiel #12
0
static int
MimeMultipart_create_child(MimeObject *obj)
{
  MimeMultipart *mult = (MimeMultipart *) obj;
  int           status;
  char *ct = (mult->hdrs
        ? MimeHeaders_get (mult->hdrs, HEADER_CONTENT_TYPE,
                 PR_TRUE, PR_FALSE)
        : 0);
  const char *dct = (((MimeMultipartClass *) obj->clazz)->default_part_type);
  MimeObject *body = NULL;

  mult->state = MimeMultipartPartFirstLine;
  /* Don't pass in NULL as the content-type (this means that the
   auto-uudecode-hack won't ever be done for subparts of a
   multipart, but only for untyped children of message/rfc822.
   */
  body = mime_create(((ct && *ct) ? ct : (dct ? dct: TEXT_PLAIN)),
           mult->hdrs, obj->options);
  PR_FREEIF(ct);
  if (!body) return MIME_OUT_OF_MEMORY;
  status = ((MimeContainerClass *) obj->clazz)->add_child(obj, body);
  if (status < 0)
  {
    mime_free(body);
    return status;
  }

#ifdef MIME_DRAFTS
  if ( obj->options && 
     obj->options->decompose_file_p &&
     obj->options->is_multipart_msg &&
     obj->options->decompose_file_init_fn )
  {
    if ( !mime_typep(obj,(MimeObjectClass*)&mimeMultipartRelatedClass) &&
           !mime_typep(obj,(MimeObjectClass*)&mimeMultipartAlternativeClass) &&
       !mime_typep(obj,(MimeObjectClass*)&mimeMultipartSignedClass) &&
#ifdef MIME_DETAIL_CHECK
       !mime_typep(body, (MimeObjectClass*)&mimeMultipartRelatedClass) &&
       !mime_typep(body, (MimeObjectClass*)&mimeMultipartAlternativeClass) &&
       !mime_typep(body,(MimeObjectClass*)&mimeMultipartSignedClass) 
#else
           /* bug 21869 -- due to the fact that we are not generating the
              correct mime class object for content-typ multipart/signed part
              the above check failed. to solve the problem in general and not
              to cause early temination when parsing message for opening as
              draft we can simply make sure that the child is not a multipart
              mime object. this way we could have a proper decomposing message
              part functions set correctly */
           !mime_typep(body, (MimeObjectClass*) &mimeMultipartClass)
#endif
    &&        ! (mime_typep(body, (MimeObjectClass*)&mimeExternalObjectClass) && !strcmp(body->content_type, "text/x-vcard"))
       )
    {
    status = obj->options->decompose_file_init_fn ( obj->options->stream_closure, mult->hdrs );
    if (status < 0) return status;
    }
  }
#endif /* MIME_DRAFTS */


  /* Now that we've added this new object to our list of children,
   start its parser going (if we want to display it.)
   */
  body->output_p = (((MimeMultipartClass *) obj->clazz)->output_child_p(obj, body));
  if (body->output_p)
  {  
    status = body->clazz->parse_begin(body);

#ifdef XP_MACOSX
    /* if we are saving an apple double attachment, we need to set correctly the conten type of the channel */
    if (mime_typep(obj, (MimeObjectClass *) &mimeMultipartAppleDoubleClass))
    {
      struct mime_stream_data *msd = (struct mime_stream_data *)body->options->stream_closure;
      if (!body->options->write_html_p && body->content_type && !PL_strcasecmp(body->content_type, APPLICATION_APPLEFILE))
      {
        if (msd && msd->channel)
          msd->channel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_APPLEFILE));
      }
    }
#endif

    if (status < 0) return status;
  }

  return 0;
}
Beispiel #13
0
int main( int argc, char **argv )
{

	// Read any command line arguments from our friend the user.
	arguments(argc, argv);

	// Catch some signals so can exit cleanly

	signal(SIGINT, exit_interrupt);
#ifndef WIN32
	signal(SIGHUP,  exit_interrupt);
	signal(SIGTERM, exit_interrupt);
	signal(SIGPIPE, SIG_IGN);
    if (debug_on)
        setvbuf(stdout, NULL, _IONBF, 0);
#endif

	printf("%s - Jorgen Lundman v%s %s %s\n\n",
		argv ? argv[0] : "llink",
		   VERSION,
		   VERSION_STRING,
#if WITH_DVDREAD
		   "(libdvdread)"
#else

#if HAVE_CLINKC
		   "(libdvdnav, ClinkC)"
#else
		   "(libdvdnav)"
#endif
#endif
		   );


	lion_buffersize(conf_buffersize);
	//lion_buffersize(2352);

	if (lion_init()) {
		printf("Failed to initialize lion/networking\n");
		exit(-1);
	}

	debugf("\n");

	// Read configuration file, if any
	// Warning, calls lion_poll until done.
	conf_init();

	debugf("[main] initialising...\n");

	// Warning, calls lion_poll until done.
	mime_init();

	// Warning, calls lion_poll until done.
	skin_init();

	ssdp_init();

	httpd_init();

	request_init();

	root_init();

	llrar_init();

	visited_init();

	cgicmd_init();

#ifdef EXTERNAL
	external_init();
#endif

	printf("[main] ready!\n");

	// Background?
#ifndef WIN32
	if (!foreground) {
		if (fork()) exit(0);
		setsid();

        if (conf_pidfile) {
            FILE *fd;
            if ((fd = fopen(conf_pidfile, "w"))) {
                fprintf(fd, "%u\r\n", getpid());
                fclose(fd);
            }
        }
	}
#endif

    cupnp_init();


	// Scan for media
	if (conf_xmlscan) {
		signal(SIGINT, SIG_DFL);
		xmlscan_run();
		do_exit = 1;
	}


	query_init();

#ifdef WIN32
	SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
#endif

	// The main loop
	while ( !do_exit ) {

        // Was 250,0 - we should probably let users control this in
        // conf settings.
		if (lion_poll(0, 1)<0) do_exit=1;

		request_events();

#ifdef EXTERNAL
		external_resume();
#endif

	}

	printf("\n[main] releasing resources...\n");

	query_free();

    cupnp_free();

#ifdef EXTERNAL
	external_free();
#endif

	root_free();

	cgicmd_free();

	visited_free();

	llrar_free();

	request_free();

	httpd_free();

	ssdp_free();

	skin_free();

	mime_free();

	conf_free();

#ifndef WIN32  // Crashed when releasing spawned processes, until i can fix:
	lion_free();
#endif

	debugf("[main] done.\n");

	return 0;

}
Beispiel #14
0
/*
 * parse a mime package
 */
MIME *mime_parse (char *buf)
{
  char *ch, *p;
  int l, c;
  MIME *m, **n;
  char boundary[100];

  /*
   * first find the header end 
   */
  if ((ch = strstr (buf, "\n\r\n")) != NULL)
    ch += 3;
  else if ((ch = strstr (buf, "\n\n")) != NULL)
    ch += 2;
  else
  {
    debug ("headers not found\n");
    return (NULL);
  }
  c = *ch;
  *ch = 0;
  m = mime_alloc ();
  m->headers = (char *) malloc (ch - buf + 1);
  strcpy (m->headers, buf);
  *ch = c;
  debug ("headers:\n%s", m->headers);
  /*
   * next determine the size 
   */
  
  if ((m->len = mime_getLength (m)) == 0)
  {
    m->len = strlen (ch);
    mime_setLength (m, m->len);
  }
  debug ("len=%d\n", m->len);
  /* 
   * copy in the body
   * if not a multipart then it's all body
   * we alloc an extra byte for the EOS
   */
  if ((l = mime_getBoundary (m, boundary, 100)) < 1)
  {
    m->body = (unsigned char *) malloc (m->len + 1);
    memmove (m->body, ch, m->len);
    m->body[m->len] = 0;
    debug ("parse completed\n");
    return (m);
  }

  /*
   * each part goes into the next chain
   */
  n = &m->next;
  p = strstr (ch - 1, boundary);
  if (p > ch -1)
  {
    m->len = p - ch;
    c = *p;
    *p = 0;
    m->body = (unsigned char *) malloc (m->len + 1);
    memmove (m->body, ch, m->len + 1);
  }
  else
    m->len = 0;
  ch = p;
  while (1)
  {
    ch += l;			/* bump past boundary marker	*/
    debug ("checking end of boundry\n");
    if ((ch[0] == ch[1]) && (ch[0] == '-'))
      break;			/* find next one		*/
    if (*ch++ == '\r') ch++;	/* bump past CR LF		*/
    if ((p = strstr (ch, boundary)) == NULL)
    {
      debug ("end boundary not found\n");
      return (mime_free (m));
    }
    c = *p;			/* parse to it			*/
    *p = 0;
    debug ("next part...\n");
    if ((*n = mime_parse (ch)) == NULL)
    {
      debug ("next part did not parse\n");
      return (mime_free (m));
    }
    n = &(*n)->next;
    *p = c;
    ch = p;			/* set up for next part		*/
  }
  debug ("parse completed\n");
  return (m);
}
Beispiel #15
0
static int
MimeEncrypted_emit_buffered_child(MimeObject *obj)
{
  MimeEncrypted *enc = (MimeEncrypted *) obj;
  int status = 0;
  char *ct = 0;
  MimeObject *body;

  NS_ASSERTION(enc->crypto_closure, "1.2 <*****@*****.**> 01 Nov 2001 17:59");

  /* Emit some HTML saying whether the signature was cool.
	 But don't emit anything if in FO_QUOTE_MESSAGE mode.

	 Also, don't emit anything if the enclosed object is itself a signed
	 object -- in the case of an encrypted object which contains a signed
	 object, we only emit the HTML once (since the normal way of encrypting
	 and signing is to nest the signature inside the crypto envelope.)
   */
  if (enc->crypto_closure &&
	  obj->options &&
	  obj->options->headers != MimeHeadersCitation &&
	  obj->options->write_html_p &&
	  obj->options->output_fn)
	  // && !mime_crypto_object_p(enc->hdrs, PR_TRUE)) // XXX fix later XXX //
	{
    char *html;
#if 0 // XXX Fix this later XXX //
	  char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html
					(enc->crypto_closure));
	  if (!html) return -1; /* MK_OUT_OF_MEMORY? */
	  
    status = MimeObject_write(obj, html, nsCRT::strlen(html), PR_FALSE);
	  PR_FREEIF(html);
	  if (status < 0) return status;
#endif

	  /* Now that we have written out the crypto stamp, the outermost header
		 block is well and truly closed.  If this is in fact the outermost
		 message, then run the post_header_html_fn now.
	   */
	  if (obj->options &&
		  obj->options->state &&
		  obj->options->generate_post_header_html_fn &&
		  !obj->options->state->post_header_html_run_p)
		{
		  MimeHeaders *outer_headers = nsnull;
		  MimeObject *p;
		  for (p = obj; p->parent; p = p->parent)
			  outer_headers = p->headers;
		  NS_ASSERTION(obj->options->state->first_data_written_p, "1.2 <*****@*****.**> 01 Nov 2001 17:59");
		  html = obj->options->generate_post_header_html_fn(NULL,
													obj->options->html_closure,
															outer_headers);
		  obj->options->state->post_header_html_run_p = PR_TRUE;
		  if (html)
			{
        status = MimeObject_write(obj, html, strlen(html), PR_FALSE);
			  PR_FREEIF(html);
			  if (status < 0) return status;
			}
		}
	}
  else if (enc->crypto_closure &&
		   obj->options &&
	   obj->options->decrypt_p)
	{
	  /* Do this just to cause `mime_set_crypto_stamp' to be called, and to
		 cause the various `decode_error' and `verify_error' slots to be set:
		 we don't actually use the returned HTML, because we're not emitting
		 HTML.  It's maybe not such a good thing that the determination of
		 whether it was encrypted or not is tied up with generating HTML,
		 but oh well. */
	  char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html
					(enc->crypto_closure));
	  PR_FREEIF(html);
	}

  if (enc->hdrs)
	ct = MimeHeaders_get (enc->hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE);
  body = mime_create((ct ? ct : TEXT_PLAIN), enc->hdrs, obj->options);
  
#ifdef MIME_DRAFTS
  if (obj->options->decompose_file_p) {
	if (mime_typep (body, (MimeObjectClass*) &mimeMultipartClass) )
		obj->options->is_multipart_msg = PR_TRUE;
	else if (obj->options->decompose_file_init_fn)
		obj->options->decompose_file_init_fn(obj->options->stream_closure,
											 enc->hdrs);
  }
#endif /* MIME_DRAFTS */

  PR_FREEIF(ct);

  if (!body) return MIME_OUT_OF_MEMORY;
  status = ((MimeContainerClass *) obj->clazz)->add_child (obj, body);
  if (status < 0)
	{
	  mime_free(body);
	  return status;
	}

  /* Now that we've added this new object to our list of children,
	 start its parser going. */
  status = body->clazz->parse_begin(body);
  if (status < 0) return status;

  /* If this object (or the parent) is being output, then by definition
	 the child is as well.  (This is only necessary because this is such
	 a funny sort of container...)
   */
  if (!body->output_p &&
	  (obj->output_p ||
	   (obj->parent && obj->parent->output_p)))
	body->output_p = PR_TRUE;

  /* If the body is being written raw (not as HTML) then make sure to
	 write its headers as well. */
  if (body->output_p && obj->output_p && !obj->options->write_html_p)
	{
	  status = MimeObject_write(body, "", 0, PR_FALSE);  /* initialize */
	  if (status < 0) return status;
	  status = MimeHeaders_write_raw_headers(body->headers, obj->options,
											 PR_FALSE);
	  if (status < 0) return status;
	}

  if (enc->part_buffer)  /* part_buffer is 0 for 0-length encrypted data. */

#ifdef MIME_DRAFTS
    if (obj->options->decompose_file_p && !obj->options->is_multipart_msg)
		status = MimePartBufferRead(enc->part_buffer,
								/* The (nsresult (*) ...) cast is to turn the `void'
								   argument into `MimeObject'. */
								 ((nsresult (*) (const char *, PRInt32, void *))
								obj->options->decompose_file_output_fn),
								obj->options->stream_closure);
    else
#endif /* MIME_DRAFTS */

	status = MimePartBufferRead(enc->part_buffer,
								/* The (nsresult (*) ...) cast is to turn the `void'
								   argument into `MimeObject'. */
								 ((nsresult (*) (const char *, PRInt32, void *))
								 body->clazz->parse_buffer),
								body);
  if (status < 0) return status;

  /* The child has been fully processed.  Close it off.
   */
  status = body->clazz->parse_eof(body, PR_FALSE);
  if (status < 0) return status;

  status = body->clazz->parse_end(body, PR_FALSE);
  if (status < 0) return status;

#ifdef MIME_DRAFTS
  if (obj->options->decompose_file_p && !obj->options->is_multipart_msg)
	  obj->options->decompose_file_close_fn(obj->options->stream_closure);
#endif /* MIME_DRAFTS */

  /* Put out a separator after every encrypted object. */
  status = MimeObject_write_separator(obj);
  if (status < 0) return status;

  MimeEncrypted_cleanup (obj, PR_FALSE);

  return 0;
}
Beispiel #16
0
static int
MimeMessage_close_headers (MimeObject *obj)
{
  MimeMessage *msg = (MimeMessage *) obj;
  int status = 0;
  char *ct = 0;      /* Content-Type header */
  MimeObject *body;

  if (msg->hdrs)
  {
    PRBool outer_p = !obj->headers; /* is this the outermost message? */


#ifdef MIME_DRAFTS
    if (outer_p &&
      obj->options &&
          (obj->options->decompose_file_p || obj->options->caller_need_root_headers) &&
      obj->options->decompose_headers_info_fn)
    {
#ifdef ENABLE_SMIME
      if (obj->options->decrypt_p && !mime_crypto_object_p (msg->hdrs, PR_FALSE))
        obj->options->decrypt_p = PR_FALSE;
#endif /* ENABLE_SMIME */
      if (!obj->options->caller_need_root_headers || (obj == obj->options->state->root))
        status = obj->options->decompose_headers_info_fn (
                         obj->options->stream_closure,
                               msg->hdrs );
    }
#endif /* MIME_DRAFTS */


    /* If this is the outermost message, we need to run the
     `generate_header' callback.  This happens here instead of
     in `parse_begin', because it's only now that we've parsed
     our headers.  However, since this is the outermost message,
     we have yet to write any HTML, so that's fine.
     */
    if (outer_p &&
      obj->output_p &&
      obj->options &&
      obj->options->write_html_p &&
      obj->options->generate_header_html_fn)
    {
      int lstatus = 0;
      char *html = 0;

      /* The generate_header_html_fn might return HTML, so it's important
       that the output stream be set up with the proper type before we
       make the MimeObject_write() call below. */
      if (!obj->options->state->first_data_written_p)
      {
        lstatus = MimeObject_output_init (obj, TEXT_HTML);
        if (lstatus < 0) return lstatus;
        PR_ASSERT(obj->options->state->first_data_written_p);
      }

      html = obj->options->generate_header_html_fn(NULL,
                           obj->options->html_closure,
                             msg->hdrs);
      if (html)
      {
        lstatus = MimeObject_write(obj, html, strlen(html), PR_FALSE);
        PR_Free(html);
        if (lstatus < 0) return lstatus;
      }
    }


    /* Find the content-type of the body of this message.
     */
    {
    PRBool ok = PR_TRUE;
    char *mv = MimeHeaders_get (msg->hdrs, HEADER_MIME_VERSION,
                  PR_TRUE, PR_FALSE);

#ifdef REQUIRE_MIME_VERSION_HEADER
    /* If this is the outermost message, it must have a MIME-Version
       header with the value 1.0 for us to believe what might be in
       the Content-Type header.  If the MIME-Version header is not
       present, we must treat this message as untyped.
     */
    ok = (mv && !strcmp(mv, "1.0"));
#else
    /* #### actually, we didn't check this in Mozilla 2.0, and checking
       it now could cause some compatibility nonsense, so for now, let's
       just believe any Content-Type header we see.
     */
    ok = PR_TRUE;
#endif

    if (ok)
      {
      ct = MimeHeaders_get (msg->hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE);

      /* If there is no Content-Type header, but there is a MIME-Version
         header, then assume that this *is* in fact a MIME message.
         (I've seen messages with

          MIME-Version: 1.0
          Content-Transfer-Encoding: quoted-printable

         and no Content-Type, and we should treat those as being of type
         MimeInlineTextPlain rather than MimeUntypedText.)
       */
      if (mv && !ct)
        ct = strdup(TEXT_PLAIN);
      }

    PR_FREEIF(mv);  /* done with this now. */
    }

    /* If this message has a body which is encrypted and we're going to
       decrypt it (whithout converting it to HTML, since decrypt_p and
       write_html_p are never true at the same time)
    */
    if (obj->output_p &&
        obj->options &&
        obj->options->decrypt_p
#ifdef ENABLE_SMIME
        && !mime_crypto_object_p (msg->hdrs, PR_FALSE)
#endif /* ENABLE_SMIME */
        )
    {
      /* The body of this message is not an encrypted object, so we need
         to turn off the decrypt_p flag (to prevent us from s#$%ing the
         body of the internal object up into one.) In this case,
         our output will end up being identical to our input.
      */
      obj->options->decrypt_p = PR_FALSE;
    }

    /* Emit the HTML for this message's headers.  Do this before
     creating the object representing the body.
     */
    if (obj->output_p &&
      obj->options &&
      obj->options->write_html_p)
    {
      /* If citation headers are on, and this is not the outermost message,
       turn them off. */
      if (obj->options->headers == MimeHeadersCitation && !outer_p)
      obj->options->headers = MimeHeadersSome;

      /* Emit a normal header block. */
      status = MimeMessage_write_headers_html(obj);
      if (status < 0) return status;
    }
    else if (obj->output_p)
    {
      /* Dump the headers, raw. */
      status = MimeObject_write(obj, "", 0, PR_FALSE);  /* initialize */
      if (status < 0) return status;
      status = MimeHeaders_write_raw_headers(msg->hdrs, obj->options,
                         obj->options->decrypt_p);
      if (status < 0) return status;
    }

#ifdef XP_UNIX
    if (outer_p && obj->output_p)
    /* Kludge from mimehdrs.c */
    MimeHeaders_do_unix_display_hook_hack(msg->hdrs);
#endif /* XP_UNIX */
  }

  /* Never put out a separator after a message header block. */
  if (obj->options && obj->options->state)
  obj->options->state->separator_suppressed_p = PR_TRUE;

#ifdef MIME_DRAFTS
  if ( !obj->headers &&    /* outer most message header */
     obj->options &&
     obj->options->decompose_file_p &&
     ct )
  obj->options->is_multipart_msg = PL_strcasestr(ct, "multipart/") != NULL;
#endif /* MIME_DRAFTS */


  body = mime_create(ct, msg->hdrs, obj->options);

  PR_FREEIF(ct);
  if (!body) return MIME_OUT_OF_MEMORY;
  status = ((MimeContainerClass *) obj->clazz)->add_child (obj, body);
  if (status < 0)
  {
    mime_free(body);
    return status;
  }

  // Only do this if this is a Text Object!
  if ( mime_typep(body, (MimeObjectClass *) &mimeInlineTextClass) )
  {
    ((MimeInlineText *) body)->needUpdateMsgWinCharset = PR_TRUE;
  }

  /* Now that we've added this new object to our list of children,
   start its parser going. */
  status = body->clazz->parse_begin(body);
  if (status < 0) return status;

  // Now notify the emitter if this is the outer most message, unless
  // it is a part that is not the head of the message. If it's a part,
  // we need to figure out the content type/charset of the part
  //
  PRBool outer_p = !obj->headers;  /* is this the outermost message? */

  if ( outer_p &&
       (!obj->options->part_to_load || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay))
  {
    // call SetMailCharacterSetToMsgWindow() to set a menu charset
    if (mime_typep(body, (MimeObjectClass *) &mimeInlineTextClass))
    {
      MimeInlineText  *text = (MimeInlineText *) body;
      if (text && text->charset && *text->charset)
        SetMailCharacterSetToMsgWindow(body, text->charset);
    }

    char  *msgID = MimeHeaders_get (msg->hdrs, HEADER_MESSAGE_ID,
                                    PR_FALSE, PR_FALSE);

    const char  *outCharset = NULL;
    if (!obj->options->force_user_charset)  /* Only convert if the user prefs is false */
      outCharset = "UTF-8";

    mimeEmitterStartBody(obj->options, (obj->options->headers == MimeHeadersNone), msgID, outCharset);
    PR_FREEIF(msgID);

  // setting up truncated message html fotter function
  char *xmoz = MimeHeaders_get(msg->hdrs, HEADER_X_MOZILLA_STATUS, PR_FALSE,
                 PR_FALSE);
  if (xmoz)
  {
    PRUint32 flags = 0;
    char dummy = 0;
    if (sscanf(xmoz, " %lx %c", &flags, &dummy) == 1 &&
      flags & MSG_FLAG_PARTIAL)
    {
      obj->options->html_closure = obj;
      obj->options->generate_footer_html_fn =
        MimeMessage_partial_message_html;
    }
    PR_FREEIF(xmoz);
  }
  }

  return 0;
}
Beispiel #17
0
int html_message(const char *list, unsigned int y, unsigned int m, unsigned int d, unsigned int n)
{
	unsigned int aday, n0, n2;
	char *list_file;
	off_t idx_offset;
	int fd, error, got, trunc, prev, next;
	idx_msgnum_t m0, m1, m1r;
	struct idx_message idx_msg[3];
	idx_off_t offset;
	idx_size_t size;
	struct buffer src, dst;
	struct mime_ctx mime;
	char *p, *q, *date, *from, *to, *cc, *subject, *body, *bend;

	if (y < MIN_YEAR || y > MAX_YEAR ||
	    m < 1 || m > 12 ||
	    d < 1 || d > 31 ||
	    n < 1 || n > 999999)
		return html_error("Invalid date or message number");
	aday = YMD2ADAY(y - MIN_YEAR, m, d);

	list_file = concat(MAIL_SPOOL_PATH "/", list, NULL);
	if (!list_file)
		return html_error(NULL);

	fd = idx_open(list);
	if (fd < 0) {
		error = errno;
		free(list_file);
		return html_error(error == ENOENT ?
		    "No such mailing list" : (error == ESRCH ?
		    "Index needs rebuild" : NULL));
	}

	error = !idx_read_aday_ok(fd, aday, &m1, sizeof(m1));
	if (error || m1 < 1 || m1 >= MAX_MAILBOX_MESSAGES) {
		idx_close(fd);
		free(list_file);
		return html_error((error || m1 > 0) ? NULL : "No such message");
	}
	m1r = m1 + n - (1 + 1); /* both m1 and n are 1-based; m1r is 0-based */
	idx_offset = IDX2MSG(m1r);
	prev = next = 1;
	if (m1r >= 1) {
		idx_offset -= sizeof(idx_msg[0]);
		got = idx_read(fd, idx_offset, &idx_msg, sizeof(idx_msg));
		if (got != sizeof(idx_msg)) {
			error = got != sizeof(idx_msg[0]) * 2;
			idx_msg[2] = idx_msg[1];
			next = 0;
		}
	} else {
		prev = 0;
		got = idx_read(fd, idx_offset, &idx_msg[1], sizeof(idx_msg[1]) * 2);
		if (got != sizeof(idx_msg[1]) * 2) {
			error = got != sizeof(idx_msg[1]);
			idx_msg[2] = idx_msg[1];
			next = 0;
		}
		idx_msg[0] = idx_msg[1];
	}

	n0 = n - 1;
	if (!n0 && prev && !error) {
		aday = YMD2ADAY(idx_msg[0].y, idx_msg[0].m, idx_msg[0].d);
		error = !idx_read_aday_ok(fd, aday, &m0, sizeof(m0));
		if (m1 > m0)
			n0 = m1 - m0;
		else
			error = 1;
	}

	if (idx_close(fd) || error) {
		free(list_file);
		return html_error(got ? NULL : "No such message");
	}

	n2 = n + 1;
	if (idx_msg[2].y != idx_msg[1].y ||
	    idx_msg[2].m != m || idx_msg[2].d != d)
		n2 = 1;

	if (y - MIN_YEAR != idx_msg[1].y ||
	    m != idx_msg[1].m || d != idx_msg[1].d) {
		free(list_file);
		return html_error("No such message");
	}

	offset = idx_msg[1].offset;
	size = idx_msg[1].size;

	trunc = size > MAX_MESSAGE_SIZE;
	if (trunc)
		size = MAX_MESSAGE_SIZE;
	if (buffer_init(&src, size)) {
		free(list_file);
		return html_error(NULL);
	}
	fd = open(list_file, O_RDONLY);
	free(list_file);
	if (fd < 0) {
		buffer_free(&src);
		return html_error("mbox open error");
	}
	error =
	    lseek(fd, offset, SEEK_SET) != offset ||
	    read_loop(fd, src.start, size) != size;
	if (close(fd) || error || mime_init(&mime, &src)) {
		buffer_free(&src);
		return html_error("mbox read error");
	}
	if (buffer_init(&dst, size)) {
		buffer_free(&src);
		mime_free(&mime);
		return html_error(NULL);
	}

	date = from = to = cc = subject = body = NULL;
	while (src.end - src.ptr > 9 && *src.ptr != '\n') {
		switch (*src.ptr) {
		case 'D':
		case 'd':
			if (!strncasecmp(src.ptr, "Date:", 5)) {
				date = mime_decode_header(&mime);
				continue;
			}
			break;
		case 'F':
		case 'f':
			if (!strncasecmp(src.ptr, "From:", 5)) {
				from = mime_decode_header(&mime);
				continue;
			}
			break;
		case 'T':
		case 't':
			if (!strncasecmp(src.ptr, "To:", 3)) {
				to = mime_decode_header(&mime);
				continue;
			}
			break;
		case 'S':
		case 's':
			if (!strncasecmp(src.ptr, "Subject:", 8)) {
				subject = mime_decode_header(&mime);
				continue;
			}
			break;
		case 'C':
		case 'c':
			if (!strncasecmp(src.ptr, "CC:", 3))
				cc = mime_decode_header(&mime);
			else
				mime_decode_header(&mime);
			continue;
		}
		mime_skip_header(&mime);
	}
	if (src.ptr >= src.end) {
		buffer_free(&src);
		buffer_free(&dst);
		mime_free(&mime);
		return html_error(NULL);
	}
	if (*src.ptr == '\n')
		body = ++src.ptr;

	if ((p = subject)) {
		while ((p = strchr(p, '['))) {
			if (strncasecmp(++p, list, strlen(list)))
				continue;
			q = p + strlen(list);
			if (*q != ']')
				continue;
			if (*++q == ' ') q++;
			memmove(--p, q, strlen(q) + 1);
		}
	}

	buffer_appends(&dst, "\n");

	if (html_flags & HTML_HEADER) {
		buffer_appends(&dst, "<title>");
		buffer_appends_html(&dst, list);
		if (subject && strlen(subject) > 9) {
			buffer_appends(&dst, " - ");
			buffer_appends_html(&dst, subject + 9);
		}
		buffer_appends(&dst, "</title>\n");
		if (html_flags & HTML_CENSOR)
			buffer_appends(&dst, "<meta name=\"robots\" content=\"noindex\">\n");
	}

	if (html_flags & HTML_BODY) {
		unsigned int attachment_count = 0;

		if (prev) {
			buffer_appends(&dst, "<a href=\"");
			if (n == 1)
				buffer_appendf(&dst, "../../../%u/%02u/%02u/",
				    MIN_YEAR + idx_msg[0].y, idx_msg[0].m, idx_msg[0].d);
			buffer_appendf(&dst, "%u\">[&lt;prev]</a> ", n0);
		}
		if (next) {
			buffer_appends(&dst, "<a href=\"");
			if (n2 == 1)
				buffer_appendf(&dst, "../../../%u/%02u/%02u/",
				    MIN_YEAR + idx_msg[2].y, idx_msg[2].m, idx_msg[2].d);
			buffer_appendf(&dst, "%u\">[next&gt;]</a> ", n2);
		}
		if (idx_msg[1].t.pn) {
			buffer_appends(&dst, "<a href=\"");
			if (idx_msg[1].t.py != idx_msg[1].y ||
			    idx_msg[1].t.pm != idx_msg[1].m ||
			    idx_msg[1].t.pd != idx_msg[1].d)
				buffer_appendf(&dst, "../../../%u/%02u/%02u/",
				    MIN_YEAR + idx_msg[1].t.py, idx_msg[1].t.pm, idx_msg[1].t.pd);
			buffer_appendf(&dst, "%u\">[&lt;thread-prev]</a> ", idx_msg[1].t.pn);
		}
		if (idx_msg[1].t.nn) {
			buffer_appends(&dst, "<a href=\"");
			if (idx_msg[1].t.ny != idx_msg[1].y ||
			    idx_msg[1].t.nm != idx_msg[1].m ||
			    idx_msg[1].t.nd != idx_msg[1].d)
				buffer_appendf(&dst, "../../../%u/%02u/%02u/",
				    MIN_YEAR + idx_msg[1].t.ny, idx_msg[1].t.nm, idx_msg[1].t.nd);
			buffer_appendf(&dst, "%u\">[thread-next&gt;]</a> ", idx_msg[1].t.nn);
		}
		buffer_appends(&dst,
		    "<a href=\".\">[day]</a>"
		    " <a href=\"..\">[month]</a>"
		    " <a href=\"../..\">[year]</a>"
		    " <a href=\"../../..\">[list]</a>\n");

		buffer_appends(&dst, "<pre style=\"white-space: pre-wrap\">\n");
		if (date)
			buffer_append_header(&dst, date);
		if (from)
			buffer_append_header(&dst, from);
		if (to)
			buffer_append_header(&dst, to);
		if (cc)
			buffer_append_header(&dst, cc);
		if (subject)
			buffer_append_header(&dst, subject);

		if (!(html_flags & HTML_CENSOR))
		do {
			if (mime.entities->boundary) {
				body = mime_next_body_part(&mime);
				if (!body || body >= src.end)
					break;
				body = mime_next_body(&mime);
			}
			if (mime.entities->boundary)
				body = NULL;
			if (!body) {
				bend = mime_skip_body(&mime);
				if (!bend)
					break;
				continue;
			}

			/* mime_decode_body() will break mime vars, so,
			 * remember them now */
			char *filename = mime.entities->filename;
			char *type = mime.entities->type;
			const int isattachment = is_attachment(&mime);
			const int isinline = is_inline(&mime);
			int skip = 0;

			body = mime_decode_body(&mime, isattachment ? RECODE_NO : RECODE_YES, &bend);
			if (!body)
				break;
			if (bend >= src.end)
				skip = trunc;
			bend = src.ptr;
			if (!skip && isattachment) {
				int text = !strncasecmp(type, "text/", 5);
				attachment_count++;
				buffer_appendf(&dst, "\n<span style=\"font-family: times;\"><strong>"
				    "%s attachment \"</strong><a href=\"%u/%u\"%s>",
				    text ? "View" : "Download", n, attachment_count,
				    text ? "" :  " rel=\"nofollow\" download");
				if (filename)
					buffer_appends_html(&dst, filename);
				buffer_appends(&dst, "</a><strong>\" of type \"</strong>");
				buffer_appends_html(&dst, type);
				buffer_appends(&dst, "<strong>\"");
				if (body)
					buffer_appendf(&dst, " (%llu bytes)", (unsigned long long)(mime.dst.ptr - body));
				buffer_appends(&dst, "</strong></span>\n");
				continue;
			} else if (!isinline) {
				skip = 1;
			} else {
				skip = 0; /* do not skip non-attachments */
			}
			if (skip) {
				buffer_appends(&dst, "\n<span style=\"font-family: times;\"><strong>"
				    "Content of type \"</strong>");
				buffer_appends_html(&dst, type);
				buffer_appends(&dst, "<strong>\" skipped</strong></span>\n");
				continue;
			}
			/* inline */
			buffer_appendc(&dst, '\n');
			buffer_append_html_generic(&dst, body, mime.dst.ptr - body, 0, 1);
			mime.dst.ptr = body;
		} while (bend < src.end && mime.entities);

		if ((html_flags & HTML_CENSOR) || trunc)
			buffer_appendf(&dst, "\n<span style=\"font-family: times;\"><strong>"
			    "Content %s</strong></span>\n", (html_flags & HTML_CENSOR) ? "removed" : "truncated");

		buffer_appends(&dst, "</pre>\n");
	}

	buffer_free(&src);

	if (mime.dst.error || dst.error) {
		mime_free(&mime);
		buffer_free(&dst);
		return html_error(NULL);
	}

	mime_free(&mime);

	return html_send(&dst);
}