13 #define LTRIM(pos) while (isspace(*pos)) { pos++; }
14 #define STRTOLOWER(str, ptr) for (ptr = str ; *ptr ; ptr++) { *ptr = tolower(*ptr); }
19 #define TRUE ((bool)(-1))
20 #define FALSE ((bool)(0))
26 FILE *fp
; // File pointer
27 long int lastLine
; // Offset of the precedent line (-1 if invalid)
28 long int currentLine
; // Offset of the current line
29 long int messageId
; // Current message Id
30 long int messageBeginning
; // Offset of the beginning of the message (FROM_ line)
32 char *line
; // Line buffer
33 bool isFrom_
; // Is the current line a From_ line ?
39 MBox
*openMBox(char *filename
)
44 fp
= fopen(filename
, "r");
49 mbox
= (MBox
*)malloc(sizeof(MBox
));
52 mbox
->currentLine
= 0;
54 mbox
->messageBeginning
= 0;
56 mbox
->isFrom_
= FALSE
;
62 void closeMBox(MBox
*mbox
)
74 /** Read a line in a file
76 char *readLine(MBox
*mbox
)
79 mbox
->lastLine
= mbox
->currentLine
;
80 mbox
->currentLine
= ftell(mbox
->fp
);
81 mbox
->isFrom_
= FALSE
;
84 mbox
->line
= (char*)malloc(1001);
86 if (!fgets(mbox
->line
, 1000, mbox
->fp
)) {
87 mbox
->currentLine
= -1;
90 length
= ftell(mbox
->fp
) - mbox
->currentLine
;
95 while (length
>= 0 && (isspace(mbox
->line
[length
]) || mbox
->line
[length
] == '\0')) {
98 mbox
->line
[length
+ 1] = '\0';
100 mbox
->isFrom_
= (strstr(mbox
->line
, "From ") == mbox
->line
);
101 if (mbox
->isFrom_
&& mbox
->messageBeginning
!= mbox
->currentLine
) {
102 mbox
->messageBeginning
= mbox
->currentLine
;
108 /** Return to the last line
110 bool lastLine(MBox
*mbox
)
112 if (mbox
->lastLine
!= -1) {
113 fseek(mbox
->fp
, mbox
->lastLine
, SEEK_SET
);
121 bool readFrom_(MBox
*mbox
)
123 if (!mbox
->isFrom_
) {
126 if (!mbox
->isFrom_
) {
134 void readMessage(MBox
*mbox
, bool display
)
136 if (!readFrom_(mbox
)) {
139 while (readLine(mbox
)) {
144 if (strstr(mbox
->line
, ">From ") == mbox
->line
) {
145 puts(mbox
->line
+ 1);
153 /** Read the headers of a message
155 void readHeaders(MBox
*mbox
, char **headers
, int hdrsize
)
157 char *current
= NULL
;
161 if (!readFrom_(mbox
)) {
164 printf("%d\n%d\n", mbox
->messageId
, mbox
->messageBeginning
);
165 while (readLine(mbox
)) {
166 if (mbox
->isFrom_
|| !strlen(mbox
->line
)) {
169 if (current
&& strlen(mbox
->line
) && isspace(*(mbox
->line
))) {
179 pos
= strchr(mbox
->line
, ':');
180 if (!pos
|| pos
== mbox
->line
) {
183 size
= pos
- mbox
->line
;
184 for (i
= 0 ; i
< hdrsize
; i
++) {
185 if (strlen(headers
[i
]) == size
&& strcasestr(mbox
->line
, headers
[i
]) == mbox
->line
) {
186 current
= (char*)malloc(size
+ 1);
187 strcpy(current
, headers
[i
]);
188 current
[size
] = '\0';
191 if (!current
&& !hdrsize
) {
192 current
= (char*)malloc(size
+ 1);
193 strncpy(current
, mbox
->line
, size
);
194 current
[size
] = '\0';
195 STRTOLOWER(current
, ptr
);
213 /** Go back to the beginning of the file
215 void rewindMBox(MBox
*mbox
)
217 fseek(mbox
->fp
, 0, SEEK_SET
);
219 mbox
->messageBeginning
= 0;
223 /** Go back to the beginning of the message
225 bool rewindMessage(MBox
*mbox
)
230 fseek(mbox
->fp
, mbox
->messageBeginning
, SEEK_SET
);
231 mbox
->currentLine
= -1;
234 return mbox
->isFrom_
;
237 /** Move to the given offset
239 bool goToOffset(MBox
*mbox
, int offset
, int index
)
241 fseek(mbox
->fp
, offset
, SEEK_SET
);
242 mbox
->currentLine
= -1;
244 mbox
->messageBeginning
= offset
;
245 mbox
->messageId
= index
;
247 if (!mbox
->isFrom_
) {
253 /** Move to the given message number
255 bool goToMessage(MBox
*mbox
, int index
)
257 if (mbox
->messageId
> index
) {
259 } else if(mbox
->messageId
== index
) {
262 } else if (!mbox
->isFrom_
) {
263 while (!feof(mbox
->fp
) && !mbox
->isFrom_
) {
266 if (feof(mbox
->fp
)) {
270 while (mbox
->messageId
< index
&& !feof(mbox
->fp
)) {
271 readMessage(mbox
, FALSE
);
273 if (mbox
->messageId
== index
) {
280 /** Display the program help
284 printf("Usage: mbox-helper [action] [options] -f filename [header1 [header2 ...]]\n"
285 "Actions: only the last action given is applied\n"
286 " -c compute the number of messages. If -p is given, process the file starting à the given offset\n"
287 " -d return the headers of the messages given with the -m option. If no header is given in the\n"
288 " command line options, all the headers are returned. The headers are return with the format:\n"
291 " MSG1_HEADER1_NAME\\n\n"
292 " MSG1_HEADER1_VALUE\\n\n"
293 " MSG1_HEADER2_NAME\\n\n"
294 " MSG2_HEADER2_VALUE\\n\n"
296 " Messages are separated by a blank line\n"
297 " -b return the body of the message given by -m (only 1 message is returned)\n"
299 " -m begin[:end] id or range of messages to process\n"
300 " -p id:pos indicate that message `id` begins at offset `pos`\n"
301 " -h print this help\n");
304 /** Display an error message
305 * This function display the giver error, then show the program help and exit the program
307 void error(char *message
)
309 fprintf(stderr
, "Invalid parameters: %s\n", message
);
316 int main(int argc
, char *argv
[])
319 int fmid
= -1, lmid
= -1;
320 int pmid
= 0, pos
= 0;
321 char *filename
= NULL
;
322 char **headers
= NULL
;
328 /* getopt variables */
330 extern int optind
, optopt
;
332 while ((c
= getopt(argc
, argv
, ":bcdp:hm:f:")) != -1) {
338 fmid
= strtol(optarg
, &endptr
, 10);
339 if (endptr
== optarg
) {
340 error("invalid message id");
342 if (*endptr
!= ':') {
345 lmid
= atoi(endptr
+ 1);
349 if ((endptr
= strchr(optarg
, ':')) != NULL
) {
350 pmid
= strtol(optarg
, &endptr
, 10);
351 if (*endptr
!= ':') {
352 error("invalid position couple given");
354 pos
= atoi(endptr
+ 1);
356 error("invalid position given");
359 case 'c': case 'd': case 'b':
366 fprintf(stderr
, "Missing argument to -%c\n", optopt
);
369 fprintf(stderr
, "Unrecognized option: -%c\n", optopt
);
375 error("no file defined");
378 setlocale(LC_ALL
, "C");
380 headerNb
= argc
- optind
;
381 headers
= (argv
+ optind
);
382 for (i
= 0 ; i
< headerNb
; i
++) {
383 STRTOLOWER(headers
[i
], endptr
);
386 mbox
= openMBox(filename
);
388 fprintf(stderr
, "can't open file '%s'", filename
);
390 if ((fmid
>= pmid
|| fmid
== -1) && pos
) {
391 if (!goToOffset(mbox
, pos
, pmid
)) {
392 fprintf(stderr
, "Offset %d do not match with a message beginning\n", pos
);
399 fprintf(stderr
, "you have to define a message number");
402 goToMessage(mbox
, fmid
);
403 readMessage(mbox
, TRUE
);
406 while (!feof(mbox
->fp
)) {
409 printf("%d\n", mbox
->messageId
+ 1);
413 fprintf(stderr
, "you have to define a message number");
416 for (i
= fmid
; i
<= lmid
; i
++) {
417 goToMessage(mbox
, i
);
418 readHeaders(mbox
, headers
, headerNb
);