14 #define LTRIM(pos) while (isspace(*pos)) { pos++; }
15 #define STRTOLOWER(str, ptr) for (ptr = str ; *ptr ; ptr++) { *ptr = tolower(*ptr); }
20 #define TRUE ((bool)(-1))
21 #define FALSE ((bool)(0))
27 FILE *fp
; // File pointer
28 long int lastLine
; // Offset of the precedent line (-1 if invalid)
29 long int currentLine
; // Offset of the current line
30 long int messageId
; // Current message Id
31 long int messageBeginning
; // Offset of the beginning of the message (FROM_ line)
33 char *line
; // Line buffer
34 bool isFrom_
; // Is the current line a From_ line ?
40 MBox
*openMBox(char *filename
)
45 fp
= fopen(filename
, "r");
50 mbox
= (MBox
*)malloc(sizeof(MBox
));
53 mbox
->currentLine
= 0;
55 mbox
->messageBeginning
= 0;
57 mbox
->isFrom_
= FALSE
;
63 void closeMBox(MBox
*mbox
)
75 /** Read a line in a file
77 char *readLine(MBox
*mbox
)
80 mbox
->lastLine
= mbox
->currentLine
;
81 mbox
->currentLine
= ftell(mbox
->fp
);
82 mbox
->isFrom_
= FALSE
;
85 mbox
->line
= (char*)malloc(1001);
87 if (!fgets(mbox
->line
, 1000, mbox
->fp
)) {
88 mbox
->currentLine
= -1;
91 length
= ftell(mbox
->fp
) - mbox
->currentLine
;
96 while (length
>= 0 && (isspace(mbox
->line
[length
]) || mbox
->line
[length
] == '\0')) {
99 mbox
->line
[length
+ 1] = '\0';
101 mbox
->isFrom_
= (strstr(mbox
->line
, "From ") == mbox
->line
);
102 if (mbox
->isFrom_
&& mbox
->messageBeginning
!= mbox
->currentLine
) {
103 mbox
->messageBeginning
= mbox
->currentLine
;
109 /** Return to the last line
111 bool lastLine(MBox
*mbox
)
113 if (mbox
->lastLine
!= -1) {
114 fseek(mbox
->fp
, mbox
->lastLine
, SEEK_SET
);
122 bool readFrom_(MBox
*mbox
)
124 if (!mbox
->isFrom_
) {
127 if (!mbox
->isFrom_
) {
135 void readMessage(MBox
*mbox
, bool display
)
137 if (!readFrom_(mbox
)) {
140 while (readLine(mbox
)) {
145 if (strstr(mbox
->line
, ">From ") == mbox
->line
) {
146 puts(mbox
->line
+ 1);
154 /** Read the headers of a message
156 void readHeaders(MBox
*mbox
, char **headers
, int hdrsize
)
158 char *current
= NULL
;
162 if (!readFrom_(mbox
)) {
165 printf("%d\n%d\n", (int)mbox
->messageId
, (int)mbox
->messageBeginning
);
166 while (readLine(mbox
)) {
167 if (mbox
->isFrom_
|| !strlen(mbox
->line
)) {
170 if (current
&& strlen(mbox
->line
) && isspace(*(mbox
->line
))) {
180 pos
= strchr(mbox
->line
, ':');
181 if (!pos
|| pos
== mbox
->line
) {
184 size
= pos
- mbox
->line
;
185 for (i
= 0 ; i
< hdrsize
; i
++) {
186 if (strlen(headers
[i
]) == size
&& strcasestr(mbox
->line
, headers
[i
]) == mbox
->line
) {
187 current
= (char*)malloc(size
+ 1);
188 strcpy(current
, headers
[i
]);
189 current
[size
] = '\0';
192 if (!current
&& !hdrsize
) {
193 current
= (char*)malloc(size
+ 1);
194 strncpy(current
, mbox
->line
, size
);
195 current
[size
] = '\0';
196 STRTOLOWER(current
, ptr
);
214 /** Go back to the beginning of the file
216 void rewindMBox(MBox
*mbox
)
218 fseek(mbox
->fp
, 0, SEEK_SET
);
220 mbox
->messageBeginning
= 0;
224 /** Go back to the beginning of the message
226 bool rewindMessage(MBox
*mbox
)
231 fseek(mbox
->fp
, mbox
->messageBeginning
, SEEK_SET
);
232 mbox
->currentLine
= -1;
235 return mbox
->isFrom_
;
238 /** Move to the given offset
240 bool goToOffset(MBox
*mbox
, int offset
, int index
)
242 fseek(mbox
->fp
, offset
, SEEK_SET
);
243 mbox
->currentLine
= -1;
245 mbox
->messageBeginning
= offset
;
246 mbox
->messageId
= index
;
248 if (!mbox
->isFrom_
) {
254 /** Move to the given message number
256 bool goToMessage(MBox
*mbox
, int index
)
258 if (mbox
->messageId
> index
) {
260 } else if(mbox
->messageId
== index
) {
263 } else if (!mbox
->isFrom_
) {
264 while (!feof(mbox
->fp
) && !mbox
->isFrom_
) {
267 if (feof(mbox
->fp
)) {
271 while (mbox
->messageId
< index
&& !feof(mbox
->fp
)) {
272 readMessage(mbox
, FALSE
);
274 if (mbox
->messageId
== index
) {
281 /** Display the program help
285 printf("Usage: mbox-helper [action] [options] -f filename [header1 [header2 ...]]\n"
286 "Actions: only the last action given is applied\n"
287 " -c compute the number of messages. If -p is given, process the file starting à the given offset\n"
288 " -d return the headers of the messages given with the -m option. If no header is given in the\n"
289 " command line options, all the headers are returned. The headers are return with the format:\n"
292 " MSG1_HEADER1_NAME\\n\n"
293 " MSG1_HEADER1_VALUE\\n\n"
294 " MSG1_HEADER2_NAME\\n\n"
295 " MSG2_HEADER2_VALUE\\n\n"
297 " Messages are separated by a blank line\n"
298 " -b return the body of the message given by -m (only 1 message is returned)\n"
300 " -m begin[:end] id or range of messages to process\n"
301 " -p id:pos indicate that message `id` begins at offset `pos`\n"
302 " -h print this help\n");
305 /** Display an error message
306 * This function display the giver error, then show the program help and exit the program
308 void error(char *message
)
310 fprintf(stderr
, "Invalid parameters: %s\n", message
);
317 int main(int argc
, char *argv
[])
320 int fmid
= -1, lmid
= -1;
321 int pmid
= 0, pos
= 0;
322 char *filename
= NULL
;
323 char **headers
= NULL
;
329 /* getopt variables */
331 extern int optind
, optopt
;
333 while ((c
= getopt(argc
, argv
, ":bcdp:hm:f:")) != -1) {
339 fmid
= strtol(optarg
, &endptr
, 10);
340 if (endptr
== optarg
) {
341 error("invalid message id");
343 if (*endptr
!= ':') {
346 lmid
= atoi(endptr
+ 1);
350 if ((endptr
= strchr(optarg
, ':')) != NULL
) {
351 pmid
= strtol(optarg
, &endptr
, 10);
352 if (*endptr
!= ':') {
353 error("invalid position couple given");
355 pos
= atoi(endptr
+ 1);
357 error("invalid position given");
360 case 'c': case 'd': case 'b':
367 fprintf(stderr
, "Missing argument to -%c\n", optopt
);
370 fprintf(stderr
, "Unrecognized option: -%c\n", optopt
);
376 error("no file defined");
379 setlocale(LC_ALL
, "C");
381 headerNb
= argc
- optind
;
382 headers
= (argv
+ optind
);
383 for (i
= 0 ; i
< headerNb
; i
++) {
384 STRTOLOWER(headers
[i
], endptr
);
387 mbox
= openMBox(filename
);
389 fprintf(stderr
, "can't open file '%s'", filename
);
391 if ((fmid
>= pmid
|| fmid
== -1) && pos
) {
392 if (!goToOffset(mbox
, pos
, pmid
)) {
393 fprintf(stderr
, "Offset %d do not match with a message beginning\n", pos
);
400 fprintf(stderr
, "you have to define a message number");
403 goToMessage(mbox
, fmid
);
404 readMessage(mbox
, TRUE
);
407 while (!feof(mbox
->fp
)) {
410 printf("%d\n", (int)(mbox
->messageId
+ 1));
414 fprintf(stderr
, "you have to define a message number");
417 for (i
= fmid
; i
<= lmid
; i
++) {
418 goToMessage(mbox
, i
);
419 readHeaders(mbox
, headers
, headerNb
);