static gboolean
vee_info_set_user_flag (CamelMessageInfo *mi,
                        const gchar *name,
                        gboolean value)
{
	gint res = FALSE;
	CamelVeeFolder *vf = (CamelVeeFolder *) camel_folder_summary_get_folder (mi->summary);

	if (camel_debug("vfolderexp"))
		printf (
			"Expression for vfolder '%s' is '%s'\n",
			camel_folder_get_full_name (camel_folder_summary_get_folder (mi->summary)),
			g_strescape (vf->expression, ""));

	if (mi->uid) {
		CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, mi->uid + 8);

		HANDLE_NULL_INFO (FALSE);

		/* ignore changes done in the folder itself,
		 * unless it's a vTrash or vJunk folder */
		if (!CAMEL_IS_VTRASH_FOLDER (vf))
			camel_vee_folder_ignore_next_changed_event (vf, camel_folder_summary_get_folder (rmi->summary));

		res = camel_message_info_set_user_flag (rmi, name, value);

		camel_message_info_free (rmi);
	}

	return res;
}
Exemplo n.º 2
0
static void
mail_printer_print_finished_cb (WebKitPrintOperation *print_operation,
                                GTask *task)
{
	AsyncContext *async_context;

	if (camel_debug ("webkit:preview"))
		printf ("%s\n", G_STRFUNC);

	async_context = g_task_get_task_data (task);
	g_return_if_fail (async_context != NULL);
	async_context->print_result = GTK_PRINT_OPERATION_RESULT_APPLY;

	g_task_return_boolean (task, TRUE);
	g_object_unref (task);
}
static gboolean
vee_info_set_flags (CamelMessageInfo *mi,
                    guint32 flags,
                    guint32 set)
{
	gint res = FALSE;
	CamelVeeFolder *vf = CAMEL_VEE_FOLDER (camel_folder_summary_get_folder (mi->summary));

	if (camel_debug("vfolderexp"))
		printf (
			"Expression for vfolder '%s' is '%s'\n",
			camel_folder_get_full_name (CAMEL_FOLDER (vf)),
			g_strescape (vf->expression, ""));

	/* first update original message info... */
	if (mi->uid) {
		CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, mi->uid + 8);

		HANDLE_NULL_INFO (FALSE);

		/* ignore changes done in the folder itself,
		 * unless it's a vTrash or vJunk folder */
		if (!CAMEL_IS_VTRASH_FOLDER (vf))
			camel_vee_folder_ignore_next_changed_event (vf, camel_folder_summary_get_folder (rmi->summary));

		camel_folder_freeze (camel_folder_summary_get_folder (rmi->summary));
		res = camel_message_info_set_flags (rmi, flags, set);
		((CamelVeeMessageInfo *) mi)->old_flags = camel_message_info_flags (rmi);
		camel_folder_thaw (camel_folder_summary_get_folder (rmi->summary));

		camel_message_info_free (rmi);
	}

	if (res)
		CAMEL_FOLDER_SUMMARY_CLASS (camel_vee_summary_parent_class)->info_set_flags (mi, flags, set);

	return res;
}
Exemplo n.º 4
0
static void
mail_printer_print_failed_cb (WebKitPrintOperation *print_operation,
                              GError *error,
                              GTask *task)
{
	AsyncContext *async_context;

	if (camel_debug ("webkit:preview"))
		printf ("%s\n", G_STRFUNC);

	async_context = g_task_get_task_data (task);
	g_return_if_fail (async_context != NULL);
	async_context->print_result = GTK_PRINT_OPERATION_RESULT_ERROR;

	if (error != NULL)
		g_task_return_error (task, error);
	else {
		g_warning ("WebKit print operation returned ERROR result without setting a GError");
		g_task_return_boolean (task, FALSE);
	}

	g_object_unref (task);
}
static gboolean
vee_info_set_user_flag (CamelMessageInfo *mi, const gchar *name, gboolean value)
{
	gint res = FALSE;
	gboolean hacked_unread_folder = FALSE;
	CamelVeeFolder *vf = (CamelVeeFolder *)mi->summary->folder;

	if (camel_debug("vfolderexp"))
		printf (
			"Expression for vfolder '%s' is '%s'\n",
			camel_folder_get_full_name (mi->summary->folder),
			g_strescape (vf->expression, ""));

	if (camel_vee_folder_get_unread_vfolder (vf) == -1)
		camel_vee_summary_load_check_unread_vfolder (CAMEL_VEE_SUMMARY (mi->summary));

	if (camel_vee_folder_get_unread_vfolder (vf) == 1)
		hacked_unread_folder = TRUE;

	if (mi->uid) {
		CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
		HANDLE_NULL_INFO (FALSE);

		if (hacked_unread_folder)
			camel_vee_folder_mask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder);

		res = camel_message_info_set_user_flag (rmi, name, value);

		if (hacked_unread_folder)
			camel_vee_folder_unmask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder);

		camel_message_info_free (rmi);
	}

	return res;
}
Exemplo n.º 6
0
static CamelSExpResult *
junk_test (struct _CamelSExp *f,
           gint argc,
           struct _CamelSExpResult **argv,
           FilterMessageSearch *fms)
{
	CamelSExpResult *r;
	CamelMessageInfo *info = fms->info;
	CamelJunkFilter *junk_filter;
	CamelMessageFlags flags;
	CamelMimeMessage *message;
	CamelJunkStatus status;
	const GHashTable *ht;
	const struct _camel_header_param *node;
	gboolean sender_is_known;
	gboolean message_is_junk = FALSE;
	GError *error = NULL;

	junk_filter = camel_session_get_junk_filter (fms->session);
	if (junk_filter == NULL)
		goto exit;

	/* Check if the message is already classified. */

	flags = camel_message_info_flags (info);

	if (flags & CAMEL_MESSAGE_JUNK) {
		if (camel_debug ("junk"))
			printf (
				"Message has a Junk flag set already, "
				"skipping junk test...\n");
		goto exit;
	}

	if (flags & CAMEL_MESSAGE_NOTJUNK) {
		if (camel_debug ("junk"))
			printf (
				"Message has a NotJunk flag set already, "
				"skipping junk test...\n");
		goto exit;
	}

	/* Check the headers for a junk designation. */

	ht = camel_session_get_junk_headers (fms->session);
	node = camel_message_info_headers (info);

	while (node != NULL) {
		const gchar *value = NULL;

		if (node->name != NULL)
			value = g_hash_table_lookup (
				(GHashTable *) ht, node->name);

		message_is_junk =
			(value != NULL) &&
			(camel_strstrcase (node->value, value) != NULL);

		if (message_is_junk) {
			if (camel_debug ("junk"))
				printf (
					"Message contains \"%s: %s\"",
					node->name, value);
			goto done;
		}

		node = node->next;
	}

	/* If the sender is known, the message is not junk. */

	sender_is_known = camel_session_lookup_addressbook (
		fms->session, camel_message_info_from (info));
	if (camel_debug ("junk"))
		printf (
			"Sender '%s' in book? %d\n",
			camel_message_info_from (info),
			sender_is_known);
	if (sender_is_known)
		goto done;

	/* Consult 3rd party junk filtering software. */

	message = camel_filter_search_get_message (fms, f);
	status = camel_junk_filter_classify (
		junk_filter, message, NULL, &error);

	if (error == NULL) {
		const gchar *status_desc;

		switch (status) {
			case CAMEL_JUNK_STATUS_INCONCLUSIVE:
				status_desc = "inconclusive";
				message_is_junk = FALSE;
				break;
			case CAMEL_JUNK_STATUS_MESSAGE_IS_JUNK:
				status_desc = "junk";
				message_is_junk = TRUE;
				break;
			case CAMEL_JUNK_STATUS_MESSAGE_IS_NOT_JUNK:
				status_desc = "not junk";
				message_is_junk = FALSE;
				break;
			default:
				g_warn_if_reached ();
				status_desc = "invalid";
				message_is_junk = FALSE;
				break;
		}

		if (camel_debug ("junk"))
			g_print (
				"Junk filter classification: %s\n",
				status_desc);
	} else {
		g_warn_if_fail (status == CAMEL_JUNK_STATUS_ERROR);
		g_warning ("%s: %s", G_STRFUNC, error->message);
		g_error_free (error);
		message_is_junk = FALSE;
	}

done:
	if (camel_debug ("junk"))
		printf (
			"Message is determined to be %s\n",
			message_is_junk ? "*JUNK*" : "clean");

exit:
	r = camel_sexp_result_new (f, CAMEL_SEXP_RES_BOOL);
	r->value.number = message_is_junk;

	return r;
}
static gboolean
vee_info_set_flags (CamelMessageInfo *mi,
                    guint32 flags,
                    guint32 set)
{
	gint res = FALSE;
	CamelVeeFolder *vf = (CamelVeeFolder *)mi->summary->folder;
	gboolean hacked_unread_folder = FALSE;

	if (camel_debug("vfolderexp"))
		printf (
			"Expression for vfolder '%s' is '%s'\n",
			camel_folder_get_full_name (mi->summary->folder),
			g_strescape (vf->expression, ""));

	if (camel_vee_folder_get_unread_vfolder (vf) == -1)
		camel_vee_summary_load_check_unread_vfolder (CAMEL_VEE_SUMMARY (mi->summary));

	if (camel_vee_folder_get_unread_vfolder (vf) == 1)
		hacked_unread_folder = TRUE;

	if (mi->uid) {
		guint32 old_visible, visible, old_unread;
		CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
		CamelVeeSummary *vsummary = (CamelVeeSummary *)mi->summary;

		HANDLE_NULL_INFO (FALSE);

		old_visible = rmi->summary->visible_count;
		old_unread = mi->summary->unread_count;
		camel_folder_summary_update_counts_by_flags (mi->summary, camel_message_info_flags (rmi), TRUE);

		if (hacked_unread_folder)
			camel_vee_folder_mask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder);

		camel_folder_freeze (rmi->summary->folder);
		res = camel_message_info_set_flags (rmi, flags, set);
		((CamelVeeMessageInfo *) mi)->old_flags = camel_message_info_flags (rmi);
		camel_folder_thaw (rmi->summary->folder);

		if (hacked_unread_folder)
			camel_vee_folder_unmask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder);

		visible = rmi->summary->visible_count;

		/* Keep the summary in sync */
		camel_folder_summary_update_counts_by_flags (mi->summary, camel_message_info_flags (rmi), FALSE);

		if (hacked_unread_folder && !vsummary->fake_visible_count)
			vsummary->fake_visible_count = mi->summary->visible_count;

		if (vsummary->fake_visible_count || hacked_unread_folder)
			vsummary->fake_visible_count += visible - old_visible;

		d(printf("VF %d %d %d %d %d\n", mi->summary->unread_count, mi->summary->deleted_count, mi->summary->junk_count, mi->summary->junk_not_deleted_count, mi->summary->visible_count));

		/* This is where the ugly-created-hack is used */
		if (hacked_unread_folder && mi->summary->unread_count - old_unread != 0) {
			CamelFolderChangeInfo *changes = camel_folder_change_info_new ();
			GPtrArray *match, *array;

			camel_folder_change_info_change_uid (changes, mi->uid);

			array = g_ptr_array_new ();
			g_ptr_array_add (array, (gpointer)rmi->uid);

			match = camel_folder_search_by_uids (rmi->summary->folder, vf->expression, array, NULL);
			if ((match && !match->len) || !match) {
				vsummary->fake_visible_count--;
			} else {
				vsummary->fake_visible_count++;
			}

			g_ptr_array_free (array, TRUE);
			if (match)
				camel_folder_search_free (rmi->summary->folder, match);

			camel_folder_changed (mi->summary->folder, changes);
			camel_folder_change_info_free (changes);
		}
		camel_message_info_free (rmi);
	}

	return res;
}
/* Given a line that is the start of an untagged response, read and
 * return the complete response, which may include an arbitrary number
 * of literals.
 */
static char *
imap_read_untagged (CamelImapStore *store, char *line, CamelException *ex)
{
	int fulllen, ldigits, nread, n, i, sexp = 0;
	unsigned int length;
	GPtrArray *data;
	GString *str;
	char *end, *p, *s, *d;

	p = strrchr (line, '{');
	if (!p)
		return line;

	data = g_ptr_array_new ();
	fulllen = 0;

	while (1) {
		str = g_string_new (line);
		g_free (line);
		fulllen += str->len;
		g_ptr_array_add (data, str);

		if (!(p = strrchr (str->str, '{')) || p[1] == '-')
			break;

		/* HACK ALERT: We scan the non-literal part of the string, looking for possible s expression braces.
		   This assumes we're getting s-expressions, which we should be.
		   This is so if we get a blank line after a literal, in an s-expression, we can keep going, since
		   we do no other parsing at this level.
		   TODO: handle quoted strings? */
		for (s=str->str; s<p; s++) {
			if (*s == '(')
				sexp++;
			else if (*s == ')')
				sexp--;
		}

		length = strtoul (p + 1, &end, 10);
		if (*end != '}' || *(end + 1) || end == p + 1 || length >= UINT_MAX - 2)
			break;
		ldigits = end - (p + 1);

		/* Read the literal */
		str = g_string_sized_new (length + 2);
		str->str[0] = '\n';
		nread = 0;

		do {
			if ((n = camel_stream_read (store->istream, str->str + nread + 1, length - nread)) == -1) {
				if (errno == EINTR)
					camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
							     _("Operation cancelled"));
				else
					camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
							     g_strerror (errno));
				camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
				g_string_free (str, TRUE);
				goto lose;
			}

			nread += n;
		} while (n > 0 && nread < length);

		if (nread < length) {
			camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
					     _("Server response ended too soon."));
			camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
			g_string_free (str, TRUE);
			goto lose;
		}
		str->str[length + 1] = '\0';

		if (camel_debug("imap")) {
			printf("Literal: -->");
			fwrite(str->str+1, 1, length, stdout);
			printf("<--\n");
		}

		/* Fix up the literal, turning CRLFs into LF. Also, if
		 * we find any embedded NULs, strip them. This is
		 * dubious, but:
		 *   - The IMAP grammar says you can't have NULs here
		 *     anyway, so this will not affect our behavior
		 *     against any completely correct server.
		 *   - WU-imapd 12.264 (at least) will cheerily pass
		 *     NULs along if they are embedded in the message
		 */

		s = d = str->str + 1;
		end = str->str + 1 + length;
		while (s < end) {
			while (s < end && *s == '\0') {
				s++;
				length--;
			}
			if (*s == '\r' && *(s + 1) == '\n') {
				s++;
				length--;
			}
			*d++ = *s++;
		}
		*d = '\0';
		str->len = length + 1;

		/* p points to the "{" in the line that starts the
		 * literal. The length of the CR-less response must be
		 * less than or equal to the length of the response
		 * with CRs, therefore overwriting the old value with
		 * the new value cannot cause an overrun. However, we
		 * don't want it to be shorter either, because then the
		 * GString's length would be off...
		 */
		sprintf (p, "{%0*u}", ldigits, length);

		fulllen += str->len;
		g_ptr_array_add (data, str);

		/* Read the next line. */
		do {
			if (camel_imap_store_readline (store, &line, ex) < 0)
				goto lose;

			/* MAJOR HACK ALERT, gropuwise sometimes sends an extra blank line after literals, check that here
			   But only do it if we're inside an sexpression */
			if (line[0] == 0 && sexp > 0)
				g_warning("Server sent empty line after a literal, assuming in error");
		} while (line[0] == 0 && sexp > 0);
	}

	/* Now reassemble the data. */
	p = line = g_malloc (fulllen + 1);
	for (i = 0; i < data->len; i++) {
		str = data->pdata[i];
		memcpy (p, str->str, str->len);
		p += str->len;
		g_string_free (str, TRUE);
	}
	*p = '\0';
	g_ptr_array_free (data, TRUE);
	return line;

 lose:
	for (i = 0; i < data->len; i++)
		g_string_free (data->pdata[i], TRUE);
	g_ptr_array_free (data, TRUE);
	return NULL;
}
Exemplo n.º 9
0
/**
 * camel_scalix_stream_next_token:
 * @stream: scalix stream
 * @token: scalix token
 *
 * Reads the next token from the scalix stream and saves it in @token.
 *
 * Returns 0 on success or -1 on fail.
 **/
int
camel_scalix_stream_next_token (CamelSCALIXStream *stream, camel_scalix_token_t *token)
{
	register unsigned char *inptr;
	unsigned char *inend, *start, *p;
	gboolean escaped = FALSE;
	size_t literal = 0;
	guint32 nz_number;
	int ret;
	
	g_return_val_if_fail (CAMEL_IS_SCALIX_STREAM (stream), -1);
	g_return_val_if_fail (stream->mode != CAMEL_SCALIX_STREAM_MODE_LITERAL, -1);
	g_return_val_if_fail (token != NULL, -1);
	
	if (stream->have_unget) {
		memcpy (token, &stream->unget, sizeof (camel_scalix_token_t));
		stream->have_unget = FALSE;
		return 0;
	}
	
	token_clear (stream);
	
	inptr = stream->inptr;
	inend = stream->inend;
	*inend = '\0';
	
	do {
		if (inptr == inend) {
			if ((ret = scalix_fill (stream)) < 0) {
				token->token = CAMEL_SCALIX_TOKEN_ERROR;
				return -1;
			} else if (ret == 0) {
				token->token = CAMEL_SCALIX_TOKEN_NO_DATA;
				return 0;
			}
			
			inptr = stream->inptr;
			inend = stream->inend;
			*inend = '\0';
		}
		
		while (*inptr == ' ' || *inptr == '\r')
			inptr++;
	} while (inptr == inend);
	
	do {
		if (inptr < inend) {
			if (*inptr == '"') {
				/* qstring token */
				escaped = FALSE;
				start = inptr;
				
				/* eat the beginning " */
				inptr++;
				
				p = inptr;
				while (inptr < inend) {
					if (*inptr == '"' && !escaped)
						break;
					
					if (*inptr == '\\' && !escaped) {
						token_save (stream, p, inptr - p);
						escaped = TRUE;
						inptr++;
						p = inptr;
					} else {
						inptr++;
						escaped = FALSE;
					}
				}
				
				token_save (stream, p, inptr - p);
				
				if (inptr == inend) {
					stream->inptr = start;
					goto refill;
				}
				
				/* eat the ending " */
				inptr++;
				
				/* nul-terminate the atom token */
				token_save (stream, "", 1);
				
				token->token = CAMEL_SCALIX_TOKEN_QSTRING;
				token->v.qstring = stream->tokenbuf;
				
				d(fprintf (stderr, "token: \"%s\"\n", token->v.qstring));
				
				break;
			} else if (strchr ("+*()[]\n", *inptr)) {
				/* special character token */
				token->token = *inptr++;
				
				if (camel_debug ("scalix:stream")) {
					if (token->token != '\n')
						fprintf (stderr, "token: %c\n", token->token);
					else
						fprintf (stderr, "token: \\n\n");
				}
				
				break;
			} else if (*inptr == '{') {
				/* literal identifier token */
				if ((p = strchr (inptr, '}')) && strchr (p, '\n')) {
					inptr++;
					
					while (isdigit ((int) *inptr) && literal < UINT_MAX / 10)
						literal = (literal * 10) + (*inptr++ - '0');
					
					if (*inptr != '}') {
						if (isdigit ((int) *inptr))
							g_warning ("illegal literal identifier: literal too large");
						else if (*inptr != '+')
							g_warning ("illegal literal identifier: garbage following size");
						
						while (*inptr != '}')
							inptr++;
					}
					
					/* skip over '}' */
					inptr++;
					
					/* skip over any trailing whitespace */
					while (*inptr == ' ' || *inptr == '\r')
						inptr++;
					
					if (*inptr != '\n') {
						g_warning ("illegal token following literal identifier: %s", inptr);
						
						/* skip ahead to the eoln */
						inptr = strchr (inptr, '\n');
					}
					
					/* skip over '\n' */
					inptr++;
					
					token->token = CAMEL_SCALIX_TOKEN_LITERAL;
					token->v.literal = literal;
					
					d(fprintf (stderr, "token: {%zu}\n", literal));
					
					stream->mode = CAMEL_SCALIX_STREAM_MODE_LITERAL;
					stream->literal = literal;
					stream->eol = FALSE;
					
					break;
				} else {
					stream->inptr = inptr;
					goto refill;
				}
			} else if (*inptr >= '0' && *inptr <= '9') {
				/* number token */
				*inend = '\0';
				nz_number = strtoul ((char *) inptr, (char **) &start, 10);
				if (start == inend)
					goto refill;
				
				if (*start == ':' || *start == ',') {
					/* workaround for 'set' tokens (APPENDUID / COPYUID) */
					goto atom_token;
				}
				
				inptr = start;
				token->token = CAMEL_SCALIX_TOKEN_NUMBER;
				token->v.number = nz_number;
				
				d(fprintf (stderr, "token: %u\n", nz_number));
				
				break;
			} else if (is_atom (*inptr)) {
			atom_token:
				/* simple atom token */
				start = inptr;
				
				while (inptr < inend && is_atom (*inptr))
					inptr++;
				
				if (inptr == inend) {
					stream->inptr = start;
					goto refill;
				}
				
				token_save (stream, start, inptr - start);
				
				/* nul-terminate the atom token */
				token_save (stream, "", 1);
				
				if (!strcmp (stream->tokenbuf, "NIL")) {
					/* special atom token */
					token->token = CAMEL_SCALIX_TOKEN_NIL;
					d(fprintf (stderr, "token: NIL\n"));
				} else {
					token->token = CAMEL_SCALIX_TOKEN_ATOM;
					token->v.atom = stream->tokenbuf;
					d(fprintf (stderr, "token: %s\n", token->v.atom));
				}
				
				break;
			} else if (*inptr == '\\') {
				/* possible flag token ("\" atom) */
				start = inptr++;
				
				while (inptr < inend && is_atom (*inptr))
					inptr++;
				
				if (inptr == inend) {
					stream->inptr = start;
					goto refill;
				}
				
				/* handle the \* case */
				if ((inptr - start) == 1 && *inptr == '*')
					inptr++;
				
				if ((inptr - start) > 1) {
					token_save (stream, start, inptr - start);
					
					/* nul-terminate the flag token */
					token_save (stream, "", 1);
					
					token->token = CAMEL_SCALIX_TOKEN_FLAG;
					token->v.atom = stream->tokenbuf;
					d(fprintf (stderr, "token: %s\n", token->v.atom));
				} else {
					token->token = '\\';
					d(fprintf (stderr, "token: %c\n", token->token));
				}
				break;
			} else if (is_lwsp (*inptr)) {
				inptr++;
			} else {
				/* unknown character token? */
				token->token = *inptr++;
				d(fprintf (stderr, "token: %c\n", token->token));
				break;
			}
		} else {
		refill:
			token_clear (stream);
			
			if (scalix_fill (stream) <= 0) {
				token->token = CAMEL_SCALIX_TOKEN_ERROR;
				return -1;
			}
			
			inptr = stream->inptr;
			inend = stream->inend;
			*inend = '\0';
		}
	} while (inptr < inend);
	
	stream->inptr = inptr;
	
	return 0;
}
static CamelSExpResult *
junk_test (struct _CamelSExp *f,
           gint argc,
           struct _CamelSExpResult **argv,
           FilterMessageSearch *fms)
{
	CamelSExpResult *r;
	gboolean retval = FALSE;
	CamelMessageInfo *info = fms->info;
	CamelJunkFilter *junk_filter;

	junk_filter = camel_session_get_junk_filter (fms->session);

	d(printf("doing junk test for message from '%s'\n", camel_message_info_from (fms->info)));
	if (junk_filter != NULL && (camel_message_info_flags (info) & (CAMEL_MESSAGE_JUNK | CAMEL_MESSAGE_NOTJUNK)) == 0) {
		const GHashTable *ht = camel_session_get_junk_headers (fms->session);
		const struct _camel_header_param *node = camel_message_info_headers (info);

		while (node && !retval) {
			if (node->name) {
				gchar *value = (gchar *) g_hash_table_lookup ((GHashTable *) ht, node->name);
				d(printf("JunkCheckMatch: %s %s %s\n", node->name, node->value, value));
				if (value)
					retval = camel_strstrcase (node->value, value) != NULL;

			}
			node = node->next;
		}
		if (camel_debug ("junk"))
			printf("filtered based on junk header ? %d\n", retval);
		if (!retval) {
			retval = camel_session_lookup_addressbook (fms->session, camel_message_info_from (info)) != TRUE;
			if (camel_debug ("junk"))
				printf("Sender '%s' in book? %d\n", camel_message_info_from (info), !retval);

			if (retval) /* Not in book. Could be spam. So check for it */ {
				CamelMimeMessage *message;
				CamelJunkStatus status;
				gboolean success;

				d(printf("filtering message\n"));
				message = camel_filter_search_get_message (fms, f);
				success = camel_junk_filter_classify (junk_filter, message, &status, NULL, NULL);
				retval = success && (status == CAMEL_JUNK_STATUS_MESSAGE_IS_JUNK);
			}
		}

		if (camel_debug ("junk"))
			printf("junk filter => %s\n", retval ? "*JUNK*" : "clean");
	} else if (junk_filter != NULL && camel_debug ("junk")) {
		if (camel_message_info_flags (info) & CAMEL_MESSAGE_JUNK)
			printf ("Message has a Junk flag set already, skipping junk test...\n");
		else if (camel_message_info_flags (info) & CAMEL_MESSAGE_NOTJUNK)
			printf ("Message has a NotJunk flag set already, skipping junk test...\n");
	}

	r = camel_sexp_result_new (f, CAMEL_SEXP_RES_BOOL);
	r->value.number = retval;

	return r;
}