[Commits] Makefile.am NONE 1.1.2.1 clamd-plugin.c NONE 1.1.2.1 clamd-plugin.h NONE 1.1.2.1

colin at claws-mail.org colin at claws-mail.org
Sun Feb 17 22:21:59 CET 2013


Update of /home/claws-mail/claws/src/plugins/clamd/libclamd
In directory srv:/tmp/cvs-serv7104/src/plugins/clamd/libclamd

Added Files:
      Tag: gtk2
	Makefile.am clamd-plugin.c clamd-plugin.h 
Log Message:
2013-02-17 [colin]	3.9.0cvs75

	* src/plugins/Makefile.am
	* src/plugins/archive/Makefile.am
	* src/plugins/clamd/Makefile.am
	* src/plugins/clamd/clamav_plugin.c
	* src/plugins/clamd/clamav_plugin.h
	* src/plugins/clamd/clamav_plugin_gtk.c
	* src/plugins/clamd/placeholder.txt
	* src/plugins/clamd/libclamd/Makefile.am
	* src/plugins/clamd/libclamd/clamd-plugin.c
	* src/plugins/clamd/libclamd/clamd-plugin.h
	* src/plugins/fetchinfo/Makefile.am
	* src/plugins/fetchinfo/fetchinfo_plugin.c
	* src/plugins/fetchinfo/fetchinfo_plugin.h
	* src/plugins/fetchinfo/fetchinfo_plugin_gtk.c
	* src/plugins/fetchinfo/placeholder.txt
	* src/plugins/gdata/Makefile.am
	* src/plugins/gdata/cm_gdata_contacts.c
	* src/plugins/gdata/cm_gdata_contacts.h
	* src/plugins/gdata/cm_gdata_prefs.c
	* src/plugins/gdata/cm_gdata_prefs.h
	* src/plugins/gdata/gdata_plugin.c
	* src/plugins/gdata/gdata_plugin.h
	* src/plugins/gdata/placeholder.txt
	* src/plugins/geolocation/placeholder.txt
	* src/plugins/gtkhtml2_viewer/placeholder.txt
	* src/plugins/mailmbox/Makefile.am
	* src/plugins/mailmbox/carray.c
	* src/plugins/mailmbox/carray.h
	* src/plugins/mailmbox/chash.c
	* src/plugins/mailmbox/chash.h
	* src/plugins/mailmbox/clist.c
	* src/plugins/mailmbox/clist.h
	* src/plugins/mailmbox/mailimf.c
	* src/plugins/mailmbox/mailimf.h
	* src/plugins/mailmbox/mailimf_types.c
	* src/plugins/mailmbox/mailimf_types.h
	* src/plugins/mailmbox/mailimf_types_helper.c
	* src/plugins/mailmbox/mailimf_types_helper.h
	* src/plugins/mailmbox/mailimf_write.c
	* src/plugins/mailmbox/mailimf_write.h
	* src/plugins/mailmbox/maillock.c
	* src/plugins/mailmbox/maillock.h
	* src/plugins/mailmbox/mailmbox.c
	* src/plugins/mailmbox/mailmbox.h
	* src/plugins/mailmbox/mailmbox_folder.c
	* src/plugins/mailmbox/mailmbox_folder.h
	* src/plugins/mailmbox/mailmbox_gtk.deps
	* src/plugins/mailmbox/mailmbox_parse.c
	* src/plugins/mailmbox/mailmbox_parse.h
	* src/plugins/mailmbox/mailmbox_types.c
	* src/plugins/mailmbox/mailmbox_types.h
	* src/plugins/mailmbox/mmapstring.c
	* src/plugins/mailmbox/mmapstring.h
	* src/plugins/mailmbox/placeholder.txt
	* src/plugins/mailmbox/plugin.c
	* src/plugins/mailmbox/plugin_gtk.c
	* src/plugins/mailmbox/plugin_gtk.h
	* src/plugins/newmail/Makefile.am
	* src/plugins/newmail/newmail.c
	* src/plugins/newmail/placeholder.txt
	* src/plugins/notification/Makefile.am
	* src/plugins/notification/claws.def
	* src/plugins/notification/notification_banner.c
	* src/plugins/notification/notification_banner.h
	* src/plugins/notification/notification_command.c
	* src/plugins/notification/notification_command.h
	* src/plugins/notification/notification_core.c
	* src/plugins/notification/notification_core.h
	* src/plugins/notification/notification_foldercheck.c
	* src/plugins/notification/notification_foldercheck.h
	* src/plugins/notification/notification_hotkeys.c
	* src/plugins/notification/notification_hotkeys.h
	* src/plugins/notification/notification_indicator.c
	* src/plugins/notification/notification_indicator.h
	* src/plugins/notification/notification_lcdproc.c
	* src/plugins/notification/notification_lcdproc.h
	* src/plugins/notification/notification_pixbuf.c
	* src/plugins/notification/notification_pixbuf.h
	* src/plugins/notification/notification_plugin.c
	* src/plugins/notification/notification_plugin.h
	* src/plugins/notification/notification_popup.c
	* src/plugins/notification/notification_popup.h
	* src/plugins/notification/notification_prefs.c
	* src/plugins/notification/notification_prefs.h
	* src/plugins/notification/notification_trayicon.c
	* src/plugins/notification/notification_trayicon.h
	* src/plugins/notification/placeholder.txt
	* src/plugins/notification/plugin.def
	* src/plugins/notification/raw_claws_mail_logo_64x64.h
	* src/plugins/notification/version.rc
	* src/plugins/pdf_viewer/Makefile.am
	* src/plugins/pdf_viewer/doc_index.xpm
	* src/plugins/pdf_viewer/doc_index_close.xpm
	* src/plugins/pdf_viewer/doc_info.xpm
	* src/plugins/pdf_viewer/first_arrow.xpm
	* src/plugins/pdf_viewer/last_arrow.xpm
	* src/plugins/pdf_viewer/left_arrow.xpm
	* src/plugins/pdf_viewer/placeholder.txt
	* src/plugins/pdf_viewer/poppler_viewer.c
	* src/plugins/pdf_viewer/poppler_viewer.h
	* src/plugins/pdf_viewer/right_arrow.xpm
	* src/plugins/pdf_viewer/rotate_left.xpm
	* src/plugins/pdf_viewer/rotate_right.xpm
	* src/plugins/pdf_viewer/zoom_fit.xpm
	* src/plugins/pdf_viewer/zoom_in.xpm
	* src/plugins/pdf_viewer/zoom_out.xpm
	* src/plugins/pdf_viewer/zoom_width.xpm
	* src/plugins/perl/Makefile.am
	* src/plugins/perl/perl_gtk.c
	* src/plugins/perl/perl_gtk.h
	* src/plugins/perl/perl_plugin.c
	* src/plugins/perl/perl_plugin.h
	* src/plugins/perl/placeholder.txt
	* src/plugins/python/Makefile.am
	* src/plugins/python/clawsmailmodule.c
	* src/plugins/python/clawsmailmodule.h
	* src/plugins/python/composewindowtype.c
	* src/plugins/python/composewindowtype.h
	* src/plugins/python/foldertype.c
	* src/plugins/python/foldertype.h
	* src/plugins/python/messageinfotype.c
	* src/plugins/python/messageinfotype.h
	* src/plugins/python/nodetype.c
	* src/plugins/python/nodetype.h
	* src/plugins/python/placeholder.txt
	* src/plugins/python/python-hooks.c
	* src/plugins/python/python-hooks.h
	* src/plugins/python/python-shell.c
	* src/plugins/python/python-shell.h
	* src/plugins/python/python_plugin.c
	* src/plugins/vcalendar/Makefile.in
		Add some plugins (clamd, fetchinfo, gdata, mailmbox, newmail,
		notification, pdf_viewer, perl, python). Notification not yet
		enabled because it has too much autoconf switches for my taste.

--- NEW FILE: Makefile.am ---
INCLUDES = @GLIB_CFLAGS@ \
			@GTK_CFLAGS@ \
			-I$(top_srcdir) \
			-I$(top_builddir) \
			$(CLAWS_MAIL_CFLAGS) \
        	-I$(top_srcdir)/src \
        	-I$(top_srcdir)/src/common \
        	-I$(top_srcdir)/src/gtk

noinst_LTLIBRARIES = libclamd-plugin.la

libclamd_plugin_la_SOURCES = \
		      clamd-plugin.h \
		      clamd-plugin.c

noinst_HEADERS = clamd-plugin.h

libclamd_plugin_la_LIBADD = \
				@GLIB_LIBS@ \
				@GTK_LIBS@

--- NEW FILE: clamd-plugin.c ---
/* vim: set textwidth=80 tabstop=4: */

/*
 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
 * Copyright (C) 1999-2008 Michael Rasmussen and the Claws Mail Team
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */

#ifdef HAVE_CONFIG_H
#	include "config.h"
#endif

#include "defs.h"

#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <gtk/gtkutils.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <netdb.h>

#include "common/claws.h"
#include "common/version.h"
#include "plugin.h"
#include "utils.h"
#include "prefs.h"
#include "folder.h"
#include "prefs_gtk.h"
#include "foldersel.h"
#include "statusbar.h"
#include "alertpanel.h"
#include "clamd-plugin.h"

/* needs to be generic */
static const gchar* config_dirs[] = { 
	"/etc", 
	"/usr/local/etc",
	"/etc/clamav",
	"/usr/local/etc/clamav",
	NULL };

static const gchar* clamd_tokens[] = {
	"LocalSocket",
	"TCPSocket",
	"TCPAddr",
	NULL };

static Clamd_Socket* Socket = NULL;
static int sock;
static Config* config = NULL;

/**
 *  clamd commands used
 *  prefixing with either z or n is recommended
 *  z <=> null terminated command
 *  n <=> newline terminated command
 */
static const gchar ping[] = "nPING\n";
static const gchar version[] = "nVERSION\n";
static const gchar scan[] = "nSCAN";
static const gchar contscan[] = "nCONTSCAN";
static const gchar instream[10] = "zINSTREAM\0";

void clamd_create_config_automatic(const gchar* path) {
	FILE* conf;
	char buf[1024];
	gchar* key = NULL;
	gchar* value = NULL;

	/*debug_set_mode(TRUE);*/
	/*debug_print("%s : %s\n", folder, path);*/
	if (! path) {
		g_warning("Missing path");
		return;
	}
	if (config && config->ConfigType == AUTOMATIC &&
			config->automatic.folder &&
			strcmp(config->automatic.folder, path) == 0) {
		debug_print("%s : %s - Identical. No need to read again\n",
			config->automatic.folder, path);
		return;
	}
	if (config)
		clamd_config_free(config);
	config = clamd_config_new();
	
	config->ConfigType = AUTOMATIC;
	config->automatic.folder = g_strdup(path);
	debug_print("Opening %s to parse config file\n", path);
	conf = fopen(path, "r");
	if (!conf) {
		/*g_error("%s: Unable to open", path);*/
		alertpanel_error(_("%s: Unable to open\nclamd will be disabled"), path);
		return;
	}
	while (fgets(buf, sizeof(buf), conf)) {
		g_strstrip(buf);
		if (buf[0] == '#')
			continue;
		const gchar** tokens = clamd_tokens;
		while (*tokens) {
			const gchar* token = *tokens++;
			if ((key = g_strstr_len(buf, strlen(buf), token)) != NULL) {
				gchar* tmp = &(*(key + strlen(token)));
				tmp = g_strchug(tmp);
				gchar* end = index(tmp, '#');
				if (end)
					value = g_strndup(tmp, end - tmp);
				else
					value = g_strdup(g_strchomp(tmp));
				if (strcmp(clamd_tokens[0], token) == 0) {
					/* UNIX socket */
					Socket = (Clamd_Socket *) malloc(sizeof(Clamd_Socket *));
					if (Socket) {
						Socket->socket.path = NULL;
						Socket->socket.host = NULL;
						Socket->socket.port = -1;
						Socket->type = UNIX_SOCKET;
						Socket->socket.path = g_strdup(value);
						g_free(value);
						value = NULL;
						fclose(conf);
						debug_print("clamctl: %s\n", Socket->socket.path);
						return;
					}
				}
				else if (strcmp(clamd_tokens[1], token) == 0) {
					/* INET socket */
					if (! Socket) {
						Socket = (Clamd_Socket *) malloc(sizeof(Clamd_Socket *));
						if (Socket) {
							Socket->socket.path = NULL;
							Socket->socket.host = NULL;
							Socket->socket.port = -1;
							Socket->type = INET_SOCKET;
							Socket->socket.port = atoi(value);
							Socket->socket.host = g_strdup("localhost");
							g_free(value);
							value = NULL;
							debug_print("clamctl: %s:%d\n", 
								Socket->socket.host, Socket->socket.port);
						}
					}
					else {
						Socket->type = INET_SOCKET;
						Socket->socket.port = atoi(value);
						g_free(value);
						value = NULL;
						if (! Socket->socket.host)
							Socket->socket.host = g_strdup("localhost");
						debug_print("clamctl: %s:%d\n", 
							Socket->socket.host, Socket->socket.port);
					}
					/* We must continue since TCPAddr could also be configured */
				}
				else if (strcmp(clamd_tokens[2], token) == 0) {
					if (! Socket) {
						Socket = (Clamd_Socket *) malloc(sizeof(Clamd_Socket *));
						if (Socket) {
							Socket->socket.path = NULL;
							Socket->socket.host = NULL;
							Socket->socket.port = 3310; /* default port */
							Socket->type = INET_SOCKET;
							Socket->socket.host = g_strdup(value);
							g_free(value);
							value = NULL;
							debug_print("clamctl: %s:%d\n", 
								Socket->socket.host, Socket->socket.port);
						}
					}
					else {
						Socket->type = INET_SOCKET;
						if (Socket->socket.host)
							g_free(Socket->socket.host);
						Socket->socket.host = g_strdup(value);
						g_free(value);
						value = NULL;
						if (Socket->socket.port == -1)
							Socket->socket.port = 3310;
						debug_print("clamctl: %s:%d\n", 
							Socket->socket.host, Socket->socket.port);
					}
					/* We must continue since TCPSocket could also be configured */
				}
			}
		}
	}
	fclose(conf);
	if (! (Socket && (Socket->socket.port || Socket->socket.path))) {
		/*g_error("%s: Not able to find required information", path);*/
		alertpanel_error(_("%s: Not able to find required information\nclamd will be disabled"), path);
	}
	/*debug_set_mode(FALSE);*/
}

void clamd_create_config_manual(const gchar* host, int port) {
	if (! host || port < 1) {
		g_warning("Missing host or port < 1");
		return;
	}
	if (config && config->ConfigType == MANUAL &&
			config->manual.host && config->manual.port == port &&
			strcmp(config->manual.host, host) == 0) {
		debug_print("%s : %s and %d : %d - Identical. No need to read again\n",
			config->manual.host, host, config->manual.port, port);
		return;
	}

	if (config)
		clamd_config_free(config);
	config = clamd_config_new();
	
	config->ConfigType = MANUAL;
	config->manual.host = g_strdup(host);
	config->manual.port = port;
	/* INET socket */
	Socket = (Clamd_Socket *) malloc(sizeof(Clamd_Socket *));
	if (Socket) {
		Socket->type = INET_SOCKET;
		Socket->socket.port = port;
		Socket->socket.host = g_strdup(host);
	}
	else {
		/*g_error("%s: Not able to find required information", path);*/
		alertpanel_error(_("Could not create socket"));
	}
}

gboolean clamd_find_socket() {
	const gchar** config_dir = config_dirs;
	gchar *clamd_conf = NULL;
	
	while (*config_dir) {
		clamd_conf = g_strdup_printf("%s/clamd.conf", *config_dir++);
		debug_print("Looking for %s\n", clamd_conf);
		if (g_file_test(clamd_conf, G_FILE_TEST_EXISTS))
			break;
		g_free(clamd_conf);
		clamd_conf = NULL;
	}
	if (! clamd_conf)
		return FALSE;

	debug_print("Using %s to find configuration\n", clamd_conf);
	clamd_create_config_automatic(clamd_conf);
	g_free(clamd_conf);

	return TRUE;
}

Config* clamd_get_config() {
	return config;
}

Clamd_Socket* clamd_get_socket() {
	return Socket;
}

static void close_socket() {
	debug_print("Closing socket: %d\n", sock);
	close(sock);
}

static void create_socket() {
	struct sockaddr_un addr_u;
	struct sockaddr_in addr_i;
	struct hostent *hp;

	/*debug_set_mode(TRUE);*/
	if (! Socket) {
		sock = -1;
		return;
	}
	memset(&addr_u, 0, sizeof(addr_u));
	memset(&addr_i, 0, sizeof(addr_i));
	debug_print("socket->type: %d\n", Socket->type);
	switch (Socket->type) {
		case UNIX_SOCKET:
			debug_print("socket path: %s\n", Socket->socket.path);
			sock = socket(PF_UNIX, SOCK_STREAM, 0);
			debug_print("socket file (create): %d\n", sock);
			if (sock < 0) 
				return;
			addr_u.sun_family = AF_UNIX;
			memcpy(addr_u.sun_path, Socket->socket.path, 
					strlen(Socket->socket.path));
			if (connect(sock, (struct sockaddr *) &addr_u, sizeof(addr_u)) < 0) {
				perror("connect socket");
				close_socket();
				sock = -2;
			}
			debug_print("socket file (connect): %d\n", sock);
			break;
		case INET_SOCKET:
			addr_i.sin_family = AF_INET;
			addr_i.sin_port = htons(Socket->socket.port);
			hp = gethostbyname(Socket->socket.host);
			bcopy((void *)hp->h_addr, (void *)&addr_i.sin_addr, hp->h_length);
			sock = socket(PF_INET, SOCK_STREAM, 0);
			if (sock < 0)
				return;
			if (connect(sock, (struct sockaddr *)&addr_i, sizeof(addr_i)) < 0) {
				perror("connect socket");
				close_socket();
				sock = -2;
			}
			break;
	}
	/*debug_set_mode(FALSE);*/
}

static void copy_socket(Clamd_Socket* sock) {
	Socket = (Clamd_Socket *) malloc(sizeof(Clamd_Socket *));
	Socket->socket.path = NULL;
	Socket->socket.host = NULL;
	Socket->type = sock->type;
	if (Socket->type == UNIX_SOCKET) {
		Socket->socket.path = g_strdup(sock->socket.path);
	}
	else {
		Socket->socket.host = g_strdup(sock->socket.host);
		Socket->socket.port = sock->socket.port;
	}
}

Clamd_Stat clamd_init(Clamd_Socket* config) {
	gchar buf[BUFSIZ];
	int n_read;
	gboolean connect = FALSE;

	/*debug_set_mode(TRUE);*/
	if (config != NULL && Socket != NULL)
		return NO_SOCKET;
	if (config) {
		debug_print("socket: %s\n", config->socket.path);
		copy_socket(config);
	}
	create_socket();
	if (sock < 0) {
		debug_print("no connection\n");
		return NO_CONNECTION;
	}
	if (write(sock, ping, strlen(ping)) == -1) {
		debug_print("no connection\n");
		return NO_CONNECTION;
	}
	memset(buf, '\0', sizeof(buf));
	while ((n_read = read(sock, buf, BUFSIZ)) > 0) {
		if (buf[strlen(buf) - 1] == '\n')
			buf[strlen(buf) - 1] = '\0';
		debug_print("Ping result: %s\n", buf);
		if (strcmp("PONG", buf) == 0)
			connect = TRUE;
	}
	close_socket();
	create_socket();
	if (sock < 0) {
	    debug_print("no connection\n");
	    return NO_CONNECTION;
	}
	if (write(sock, version, strlen(version)) == -1) {
	    debug_print("no connection\n");
	    return NO_CONNECTION;
	}
	memset(buf, '\0', sizeof(buf));
        while ((n_read = read(sock, buf, BUFSIZ)) > 0) {
	    if (buf[strlen(buf) - 1] == '\n')
		buf[strlen(buf) - 1] = '\0';
	    debug_print("Version: %s\n", buf);
	}
	close_socket();
	/*debug_set_mode(FALSE);*/
	return (connect) ? OK : NO_CONNECTION;
}

static Clamd_Stat clamd_stream_scan(
		const gchar* path, gchar** res, ssize_t size) {
	int fd;
	ssize_t count;
	gchar buf[BUFSIZ];
	int n_read;
	int32_t chunk;
	
	debug_print("Scanning: %s\n", path);

	memset(buf, '\0', sizeof(buf));

	if (! res || size < 1) {
		return SCAN_ERROR;
	}
	if (! *res)
		*res = g_new(gchar, size);
	memset(*res, '\0', size);
	
	if (! g_file_test(path, G_FILE_TEST_EXISTS)) {
		*res = g_strconcat("ERROR -> ", path, _(": File does not exist"), NULL);
		debug_print("res: %s\n", *res);
		return SCAN_ERROR;
	}

#ifdef _LARGE_FILES
	fd = open(path, O_RDONLY, O_LARGEFILE);
#else
	fd = open(path, O_RDONLY);
#endif

	if (fd < 0) {
		/*g_error("%s: Unable to open", path);*/
		*res = g_strconcat("ERROR -> ", path, _(": Unable to open"), NULL);
		return SCAN_ERROR;
	}
	
	debug_print("command: %s\n", instream);
	if (write(sock, instream, strlen(instream) + 1) == -1) {
		close(fd);
		return NO_CONNECTION;
	}

	while ((count = read(fd, (void *) buf, sizeof(buf))) > 0) {
		if (count == -1) {
			close(fd);
			*res = g_strconcat("ERROR -> ", path, _("%s: Error reading"), NULL);
			return SCAN_ERROR;
		}
		if (buf[strlen(buf) - 1] == '\n')
			buf[strlen(buf) - 1] = '\0';
		debug_print("read: %ld bytes\n", count);
		
		debug_print("chunk size: %ld\n", count);
		chunk = htonl(count);
		if (write(sock, &chunk, 4) == -1) {
			close(fd);
			*res = g_strconcat("ERROR -> ", _("Socket write error"), NULL);
			return SCAN_ERROR;
		}
		if (write(sock, buf, count) == -1) {
			close(fd);
			*res = g_strconcat("ERROR -> ", _("Socket write error"), NULL);
			return SCAN_ERROR;
		}
		memset(buf, '\0', sizeof(buf));
	}
	close(fd);
	
	chunk = htonl(0);
	if (write(sock, &chunk, 4) == -1) {
		*res = g_strconcat("ERROR -> ", _("Socket write error"), NULL);
		return SCAN_ERROR;
	}
	
	debug_print("reading from socket\n");
	n_read = read(sock, *res, size);
	if (n_read < 0) {
		*res = g_strconcat("ERROR -> ", _("Socket read error"), NULL);
		return SCAN_ERROR;
	}
	debug_print("received: %s\n", *res);
	return OK;
}

Clamd_Stat clamd_verify_email(const gchar* path, response* result) {
	gchar buf[BUFSIZ];
	int n_read;
	gchar* command;
	Clamd_Stat stat;

	/*debug_set_mode(TRUE);*/
	if (!result) {
		result = malloc(sizeof(response *));
		memset(result, '\0', sizeof(response *));
	}
	create_socket();
	if (sock < 0) {
		debug_print("no connection\n");
		return NO_CONNECTION;
	}
	memset(buf, '\0', sizeof(buf));
	if (Socket->type == INET_SOCKET) {
		gchar* tmp = g_new0(gchar, BUFSIZ);
		stat = clamd_stream_scan(path, &tmp, BUFSIZ);
		if (stat != OK) {
			close_socket();
			result->msg = g_strdup(tmp);
			g_free(tmp);
			debug_print("result: %s\n", result->msg);
			/*debug_set_mode(FALSE);*/
			return stat;
		}
		debug_print("copy to buf: %s\n", tmp);
		memcpy(&buf, tmp, BUFSIZ);
		g_free(tmp);
	}
	else {
		command = g_strconcat(scan, " ", path, "\n", NULL);
		debug_print("command: %s\n", command);
		if (write(sock, command, strlen(command)) == -1) {
			debug_print("no connection\n");
			stat = NO_CONNECTION;
		}
		g_free(command);
		memset(buf, '\0', sizeof(buf));
		while ((n_read = read(sock, buf, BUFSIZ)) > 0) {
			if (buf[strlen(buf) - 1] == '\n')
				buf[strlen(buf) - 1] = '\0';
		}
	}
	debug_print("response: %s\n", buf);
	if (strstr(buf, "ERROR")) {
		stat = SCAN_ERROR;
		result->msg = g_strdup(buf);
	}		
	else if (strstr(buf, "FOUND")) {
		stat = VIRUS;
		result->msg = g_strdup(buf);
	}		
	else {
		stat = OK;
		result->msg = NULL;
	}
	close_socket();
	/*debug_set_mode(FALSE);*/

	return stat;
}

GSList* clamd_verify_dir(const gchar* path) {
	gchar buf[BUFSIZ];
	int n_read;
	gchar* command;
	GSList *list = NULL;

	if (Socket->type == INET_SOCKET)
		return list;

	create_socket();
	if (sock < 0) {
		debug_print("No socket\n");
		return list;
	}
	command = g_strconcat(contscan, path, "\n", NULL);
	debug_print("command: %s\n", command);
	if (write(sock, command, strlen(command)) == -1) {
		debug_print("No socket\n");
		return list;
	}
	g_free(command);
	memset(buf, '\0', sizeof(buf));
	while ((n_read = read(sock, buf, BUFSIZ)) > 0) {
		gchar** tmp = g_strsplit(buf, "\n", 0);
		gchar** head = tmp;
		while (*tmp) {
			gchar* file = *tmp++;
			debug_print("%s\n", file);
			if (strstr(file, "ERROR")) {
				g_warning("%s", file);
				/* dont report files with errors */
			}
			else if (strstr(file, "FOUND")) {
				list = g_slist_append(list, g_strdup(file));
			}
		}
		g_strfreev(head);
	}
	close_socket();
	return list;
}

void clamd_free_gslist(GSList* list) {
	GSList* tmp = list;
	while(tmp) {
		g_free(tmp->data);
		tmp = g_slist_next(tmp);
	}
	g_slist_free(list);
}

gchar* clamd_get_virus_name(gchar* msg) {
	gchar *head, *tail, *name;

	tail = g_strrstr_len(msg, strlen(msg), "FOUND");
	if (! tail)
		return NULL;
	head = g_strstr_len(msg, strlen(msg), ":");
	++head;
	name = g_strndup(head, tail - head);
	g_strstrip(name);
	return name;
}

void clamd_free() {
/*
 * struct _Clamd_Socket {
 *	Type type;
 *	union {
 *		struct {
 *		    gchar*  path;
 *		};
 *		struct {
 *		    gchar*  host;
 *		    int	    port;
 *		};
 *	} socket;
 *  };
 */
	if (sock > 0) {
		close_socket();
		sock = 0;
	}
	if (Socket) {
		switch (Socket->type) {
		    case UNIX_SOCKET:
			if (Socket->socket.path) {
			    g_free(Socket->socket.path);
			    Socket->socket.path = NULL;
			}
			break;
		    case INET_SOCKET:
			if (Socket->socket.host) {
			    g_free(Socket->socket.host);
			    Socket->socket.host = NULL;
			}
			break;
		}
		g_free(Socket);
		Socket = NULL;
	}
	if (config) {
	    clamd_config_free(config);
	    config = NULL;
	}
}

Config* clamd_config_new() {
	return g_new0(Config, 1);
}

void clamd_config_free(Config* c) {
	if (c->ConfigType == AUTOMATIC) {
		g_free(c->automatic.folder);
		c->automatic.folder = NULL;
	}
	else {
		g_free(c->manual.host);
		c->manual.host = NULL;
	}
	g_free(c);
}

gchar* int2char(int i) {
	gchar* s = g_new0(gchar, 5);

	sprintf(s, "%d", i);
	
	return s;
}

gchar* long2char(long l) {
	gchar* s = g_new0(gchar, 5);

	debug_print("l: %ld\n", l);
	sprintf(s, "%ld", l);
	debug_print("s: %s\n", s);
	
	return s;
}

--- NEW FILE: clamd-plugin.h ---
/* vim: set textwidth=80 tabstop=4: */

/*
 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
 * Copyright (C) 1999-2008 Michael Rasmussen and the Claws Mail Team
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */

#ifndef __CLAMD_PLUGIN_H__
#define __CLAMD_PLUGIN_H__

#include <glib.h>

typedef enum _Type Type;
enum _Type { UNIX_SOCKET, INET_SOCKET };

typedef enum _Clamd_Stat Clamd_Stat;
enum _Clamd_Stat { OK, VIRUS, NO_SOCKET, NO_CONNECTION, SCAN_ERROR };

typedef struct _Clamd_Socket Clamd_Socket;
struct _Clamd_Socket {
	Type type;
	union {
		struct {
			gchar*	path;
		};
		struct {
			gchar*	host;
			int		port;
		};
	} socket;
};

typedef struct {
	enum { AUTOMATIC, MANUAL } ConfigType;
	union {
		struct {
			gchar*	folder;
		} automatic;
		struct {
			gchar*	host;
			int		port;
		} manual;
	};
} Config;
	
typedef struct _response response;
struct _response {
	gchar* msg;
};

void clamd_create_config_automatic(const gchar* path);

void clamd_create_config_manual(const gchar* host, int port);

gchar* int2char(int i);

gchar* long2char(long l);

/**
 * Function which looks for clamd.conf the default places
 * and configures the plugin according to the information
 * found.
 * @return <b>TRUE</b> if clamd.conf found which means all
 * information need to make a connection has been found.
 * <b>FALSE</b> otherwise.
 */
gboolean clamd_find_socket();

/**
 * Function to get current configuration
 * @return the current configuration for clamd or <b>NULL</b>
 */
Config* clamd_get_config();

/**
 * Function to retrieve virus name from msg
 * @param msg Message returned from clamd
 * @return virus name or <b>NULL</b> if no virus name found
 */
gchar* clamd_get_virus_name(gchar* msg);

/**
 * Function to initialize the connection to clamd.
 * @param config A pointer to a struct _Clamd_Socket having
 * the required information. If clamd_find_socket returned
 * TRUE config should be <b>NULL</b> because all the needed
 * information is already present @see clamd_find_socket.
 * @return Clamd_Stat. @see _Clamd_Stat.
 */
Clamd_Stat clamd_init(Clamd_Socket* config);

/**
 * Function returning the current socket information.
 * @return reference to the current Clamd_Socket. @see _Clamd_Socket.
 */
Clamd_Socket* clamd_get_socket();

/**
 * Function which is checks a specific email for known viruses
 * @param path Absolut path to email to check.
 * @param msg String to which result of scan will be copied. Will be
 * <b>NULL</b> if no virus was found.
 * @return Clamd_Stat. @see _Clamd_Stat.
 */
Clamd_Stat clamd_verify_email(const gchar* path, response* result);

/**
 * Function which is checks files in a specific directory for
 * known viruses. Dont stop when a virus is found but keeps going
 * @param path Absolut path to directory to check.
 * @return list of list with virus or <b>NULL</b>.
 */
GSList* clamd_verify_dir(const gchar* path);

/**
 * Function to free all memory assigned to a GSList
 * @param list The GSList to free
 */
void clamd_free_gslist(GSList* list);

/**
 * Function which frees all memory assigned to clamd_plugin
 */
void clamd_free();

Config* clamd_config_new();

void clamd_config_free(Config* c);

#endif



More information about the Commits mailing list