1 
2 /* Dynamic loading of the sort backend.
3  * We use GLib's multiplatform dl() wrapper
4  * to open up libsortsieve and
5  * populate the global 'sort' structure.
6  *
7  * (c) 2005 Aaron Stone <aaron@serendipity.cx>
8  */
9 
10 #include "dbmail.h"
11 #define THIS_MODULE "sort"
12 
13 static sort_func *sort = NULL;
14 
15 /* Returns:
16  *  1 on modules unsupported
17  *  0 on success
18  * -1 on failure to load module
19  * -2 on missing symbols
20  * -3 on memory error
21  */
sort_load_driver(void)22 int sort_load_driver(void)
23 {
24 	GModule *module;
25 	char *lib = NULL;
26 	char *driver = NULL;
27 
28 	if (!g_module_supported()) {
29 		TRACE(TRACE_EMERG, "loadable modules unsupported on this platform");
30 		return 1;
31 	}
32 
33 	sort = g_new0(sort_func,1);
34 	if (!sort) {
35 		TRACE(TRACE_EMERG, "cannot allocate memory");
36 		return -3;
37 	}
38 
39 	/* The only supported driver is Sieve. */
40 	driver = "sort_sieve";
41 
42 	Field_T library_dir;
43 	config_get_value("library_directory", "DBMAIL", library_dir);
44 	if (strlen(library_dir) == 0) {
45 		TRACE(TRACE_DEBUG, "no value for library_directory, using default [%s]", DEFAULT_LIBRARY_DIR);
46 		snprintf(library_dir, sizeof(Field_T), "%s", DEFAULT_LIBRARY_DIR);
47 	} else {
48 		TRACE(TRACE_DEBUG, "library_directory is [%s]", library_dir);
49 	}
50 
51 	/* Try local build area, then dbmail lib paths, then system lib path. */
52 	int i;
53 	char local_path[PATH_MAX];
54 	memset(local_path, 0, sizeof(local_path));
55 	g_strlcat(local_path, DM_PWD, PATH_MAX);
56 	g_strlcat(local_path, "/src/modules/.libs", PATH_MAX);
57 
58 	char *lib_path[] = {
59 		local_path,
60 		library_dir,
61 		NULL
62 	};
63 
64 	/* Note that the limit here *includes* the NULL. This is intentional,
65 	 * to allow g_module_build_path to try the current working directory. */
66 	for (i = 0; lib_path[i] != NULL; i++) {
67 		lib = g_module_build_path(lib_path[i], driver);
68 		module = g_module_open(lib, 0); // non-lazy bind.
69 
70 		TRACE(TRACE_DEBUG, "looking for %s as %s", driver, lib);
71 		g_free(lib);
72 
73 		if (!module)
74 			TRACE(TRACE_INFO, "cannot load %s", g_module_error());
75 		if (module)
76 			break;
77 	}
78 
79 	/* If the list is exhausted without opening a module, we'll catch it,
80 	 * but we don't bomb out as we do for db and auth; just deliver normally. */
81 	if (!module) {
82 		TRACE(TRACE_EMERG, "could not load sort module - turn up debug level for details");
83 		return -1;
84 	}
85 
86 	if (!g_module_symbol(module, "sort_process",                (gpointer)&sort->process                )
87 	||  !g_module_symbol(module, "sort_validate",               (gpointer)&sort->validate               )
88 	||  !g_module_symbol(module, "sort_free_result",            (gpointer)&sort->free_result            )
89 	||  !g_module_symbol(module, "sort_listextensions",         (gpointer)&sort->listextensions         )
90 	||  !g_module_symbol(module, "sort_get_cancelkeep",         (gpointer)&sort->get_cancelkeep         )
91 	||  !g_module_symbol(module, "sort_get_reject",             (gpointer)&sort->get_reject             )
92 	||  !g_module_symbol(module, "sort_get_errormsg",           (gpointer)&sort->get_errormsg           )
93 	||  !g_module_symbol(module, "sort_get_error",              (gpointer)&sort->get_error              )
94 	||  !g_module_symbol(module, "sort_get_mailbox",            (gpointer)&sort->get_mailbox            )) {
95 		TRACE(TRACE_ERR, "cannot find function: %s: Did you enable SIEVE sorting in the DELIVERY "
96 			"section of dbmail.conf but forget to build the Sieve loadable module?", g_module_error());
97 		return -2;
98 	}
99 
100 	return 0;
101 }
102 
sort_process(uint64_t user_idnr,DbmailMessage * message,const char * mailbox)103 SortResult_T *sort_process(uint64_t user_idnr, DbmailMessage *message, const char *mailbox)
104 {
105 	if (!sort)
106 		sort_load_driver();
107 	if (!sort->process) {
108 		TRACE(TRACE_ERR, "Error loading sort driver");
109 		return NULL;
110 	}
111 	return sort->process(user_idnr, message, mailbox);
112 }
113 
sort_validate(uint64_t user_idnr,char * scriptname)114 SortResult_T *sort_validate(uint64_t user_idnr, char *scriptname)
115 {
116 	if (!sort)
117 		sort_load_driver();
118 	if (!sort->validate) {
119 		TRACE(TRACE_ERR, "Error loading sort driver");
120 		return NULL;
121 	}
122 	return sort->validate(user_idnr, scriptname);
123 }
124 
sort_listextensions(void)125 const char *sort_listextensions(void)
126 {
127 	if (!sort)
128 		sort_load_driver();
129 	if (!sort->listextensions) {
130 		TRACE(TRACE_ERR, "Error loading sort driver");
131 		return NULL;
132 	}
133 	return sort->listextensions();
134 }
135 
sort_free_result(SortResult_T * result)136 void sort_free_result(SortResult_T *result)
137 {
138 	if (!sort->free_result)
139 		return;
140 	return sort->free_result(result);
141 }
142 
sort_get_cancelkeep(SortResult_T * result)143 int sort_get_cancelkeep(SortResult_T *result)
144 {
145 	if (!sort->get_cancelkeep)
146 		return 0;
147 	return sort->get_cancelkeep(result);
148 }
149 
sort_get_reject(SortResult_T * result)150 int sort_get_reject(SortResult_T *result)
151 {
152 	if (!sort->get_reject)
153 		return 0;
154 	return sort->get_reject(result);
155 }
156 
sort_get_mailbox(SortResult_T * result)157 const char * sort_get_mailbox(SortResult_T *result)
158 {
159 	if (!sort->get_mailbox)
160 		return "";
161 	return sort->get_mailbox(result);
162 }
163 
sort_get_errormsg(SortResult_T * result)164 const char * sort_get_errormsg(SortResult_T *result)
165 {
166 	if (!sort->get_errormsg)
167 		return "";
168 	return sort->get_errormsg(result);
169 }
170 
sort_get_error(SortResult_T * result)171 int sort_get_error(SortResult_T *result)
172 {
173 	if (!sort->get_error)
174 		return 0;
175 	return sort->get_error(result);
176 }
177 
178