1
/* ifile - intelligent mail filter for EXMH/MH
2
ifile is Copyright (C) 1997 Jason Rennie <jrennie@ai.mit.edu>
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License
6
as published by the Free Software Foundation; either version 2
7
of the License, or (at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program (see file 'COPYING'); if not, write to the Free
16
Software Foundation, Inc., 59 Temple Place - Suite 330,
17
Boston, MA 02111-1307, USA.
20
#include <sys/types.h>
26
#include <ifile.h> /* standard ifile library */
28
#define SEMKEY 10439838
34
extern struct argp argp;
35
int msgs_read; /* number of messages actually read in */
37
/* variables for keeping track of time/speed of ifile */
38
clock_t DMZ_start, DMZ_end, DMZ2_start;
40
/* ifilter specific function prototypes */
41
int cmp(const void *e1, const void *e2);
44
/* written by Jason Rennie <jrennie@ai.mit.edu> */
46
main (int argc, char **argv)
48
char *data_file = NULL; /* full path of idata file */
49
char *home_dir = NULL; /* full path of user's home directory */
50
FILE *MSG = NULL; /* file pointer for a message */
51
category_rating * ratings;
53
htable *message = NULL;
55
int db_read_result = 0, db_write_result = 0;
59
setlocale(LC_ALL, "" );
61
/* Harry's semaphore stuff to protect two ifile jobs from stepping
63
/* Find the Semaphore id */
64
if ((semid = semget(SEMKEY, 1, 0666)) < 0)
65
if ((semid = semget(SEMKEY, 1, 0666|IPC_CREAT|IPC_EXCL)) < 0)
71
/* Wait for Semaphore to clear */
76
if (semop(semid, &sops, 1))
82
/* Set the Semaphore to clear on exit */
85
sops.sem_flg = SEM_UNDO;
87
if (semop(semid, &sops, 1))
93
ifile_init_args(&args);
94
argp_parse (&argp, argc, argv, 0, 0, &args);
96
ifile_verbosify(ifile_verbose, "%d file(s) passed\n", args.num_files);
97
for (i=0; i < args.num_files; i++)
98
ifile_verbosify(ifile_verbose, "file #%d: %s\n", i,
99
EXT_ARRAY_GET(args.file, char *, i));
101
/* Get home directory */
102
home_dir = getenv("HOME");
103
if (home_dir == NULL)
104
ifile_error("Fatal: HOME environment variable not defined!\n");
105
ifile_verbosify(ifile_verbose, "home directory = %s\n", home_dir);
107
/* Get the database file name */
108
if (args.db_file != NULL)
109
data_file = ifile_strdup (args.db_file);
111
data_file = ifile_sprintf("%s/%s", home_dir, DEFAULT_DB_FILE);
113
/* remove the .idata file if requested */
116
ifile_verbosify(ifile_progress, "Removing %s...\n", data_file);
117
system(ifile_sprintf("rm %s", data_file));
120
ifile_db_init(&idata);
121
ifile_open_log(argc, argv);
122
ifile_default_lexer_init();
124
/* argument variables that still need to be handled:
125
* skip_header, minus_folder, plus_folder */
127
/* Read the idata database */
128
if ((args.read_db == TRUE) && (!args.print_tokens))
129
db_read_result = ifile_read_db(data_file, &idata);
131
/* If doing update, print warning & die if folder doesn't exist */
132
if (args.plus_folder && !args.create_folder) {
136
for (; i < idata.num_folders; ++i)
137
if (strcmp(EXT_ARRAY_GET(idata.folder_name,char*,i), args.plus_folder) == 0)
140
ifile_error("Folder does not exist: %s\n", args.plus_folder);
143
/* read and lex the message(s) */
144
if (args.read_message != TRUE)
151
if (args.num_files != 0) {
153
ifile_verbosify(ifile_verbose, "Reading message %d...\n",i);
154
file_name = EXT_ARRAY_GET(args.file, char *, i);
155
MSG = fopen(file_name, "r");
158
ifile_verbosify(ifile_quiet,
159
"Not able to open %s! No action taken.\n",
161
if( message != NULL )
163
htable_free(message,free,NULL);
169
message = ifile_read_message(MSG);
170
if (args.occur == TRUE)
171
ifile_bitify_document(message);
175
if (MSG && (args.verbosity >= ifile_debug || args.print_tokens))
176
ifile_print_message(message);
177
if (MSG) fclose(MSG);
182
ifile_verbosify(ifile_quiet, "Reading message from standard input...\n");
183
message = ifile_read_message(stdin);
185
if (args.verbosity >= ifile_debug || args.print_tokens)
186
ifile_print_message(message);
189
/* Don't do anything else if we are printing tokens */
190
if (args.print_tokens)
193
/* Do LOOCV queries if requested */
194
if (args.loocv_folder != NULL)
197
ifile_error("Not able to perform LOOCV: not able to open database\n");
201
ifile_del_db(args.loocv_folder, message, &idata);
202
ratings = ifile_rate_categories(message, &idata);
203
qsort(ratings, idata.num_folders, sizeof(category_rating), cmp);
207
file_name = EXT_ARRAY_GET(args.file, char *, i);
208
ifile_concise_ratings(file_name, stdout, ratings, &idata,
212
ifile_print_ratings(stdout, ratings, &idata, args.thresh);
214
ifile_free_categories(ratings,&idata);
215
ifile_add_db(args.loocv_folder, message, &idata, args.create_folder);
218
/* if a query was requested, make the calculations and output the results */
219
if (args.query == TRUE)
222
ifile_error("Not able to perform query: not able to open database\n");
225
ratings = ifile_rate_categories(message, &idata);
226
qsort(ratings, idata.num_folders, sizeof(category_rating), cmp);
230
file_name = EXT_ARRAY_GET(args.file, char *, i);
231
ifile_concise_ratings(file_name, stdout, ratings, &idata,
235
ifile_print_ratings(stdout, ratings, &idata, args.thresh);
237
if (args.query_insert)
238
ifile_add_db(ratings[0].category, message, &idata, args.create_folder);
239
ifile_free_categories(ratings,&idata);
243
if (args.write_db == TRUE)
245
if (args.plus_folder != NULL)
247
ifile_add_db(args.plus_folder, message, &idata, args.create_folder);
249
if (args.minus_folder != NULL)
251
ifile_del_db(args.minus_folder, message, &idata);
256
htable_free(message, free, NULL);
259
} while (++i < args.num_files);
262
ifile_verbosify(ifile_progress,
263
"Read %d message(s). Time used: %.3f sec\n", msgs_read,
264
((float)(DMZ_end-DMZ_start))/CLOCKS_PER_SECOND);
266
if (args.write_db == TRUE) {
267
if ((args.plus_folder != NULL || args.query_insert == TRUE) &&
268
args.minus_folder == NULL)
270
trimmed_words = ifile_age_words(&idata, msgs_read);
271
ifile_verbosify(ifile_progress,
272
"Trimmed %d words due to lack of frequency\n",
275
db_write_result = ifile_write_db(data_file, &idata);
276
if (db_read_result != 0 && db_write_result == 0)
278
ifile_verbosify(ifile_quiet, "Created new %s file.\n", data_file);
279
/* set proper permissions */
280
system(ifile_sprintf("chmod 0600 %s\n", data_file));
287
/* if we're debugging, clean up after malloc; if not, don't bother
288
spending the computrons since we're exiting anyhow. */
289
ifile_stoplist_free();
290
ifile_db_free(&idata);
297
/* a comparison function for sorting */
298
/* Written by Jason Rennie <jrennie@ai.mit.edu> for ifile */
299
int cmp (const void *e1, const void *e2)
301
if (((category_rating *)e1)->rating > (((category_rating *)e2)->rating))
303
else if (((category_rating *)e1)->rating < (((category_rating *)e2)->rating))