* Fixed coding style.

* Fixed bug introduced with the last change: since the mbox is dumped to
  stdout, it's not a good idea to print status messages there as well.
* In the long run, I think we should replace the two conversion tools with a
  (better usable) single one.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33440 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-10-05 13:27:21 +00:00
parent 7a842ef77c
commit cc592ed1fa
+272 -334
View File
@@ -28,398 +28,336 @@
extern const char* __progname; extern const char* __progname;
static const char* kProgramName = __progname; static const char* kProgramName = __progname;
time_t DateStampTime; time_t gDateStampTime;
/* Time value used for stamping each message header. Incremented by 1 second // Time value used for stamping each message header. Incremented by 1 second
for each message, starts out with the current local time. */ // for each message, starts out with the current local time.
/****************************************************************************** /*! Global utility function to display an error message and return. The message
* Global utility function to display an error message and return. The message part describes the error, and if errorNumber is non-zero, gets the string
* part describes the error, and if ErrorNumber is non-zero, gets the string ", error code $X (standard description)." appended to it. If the message
* ", error code $X (standard description)." appended to it. If the message is NULL then it gets defaulted to "Something went wrong".
* is NULL then it gets defaulted to "Something went wrong". */
*/ static void
DisplayErrorMessage(const char* messageString = NULL, status_t errorNumber = 0,
static void DisplayErrorMessage ( const char* titleString = NULL)
const char *MessageString = NULL,
int ErrorNumber = 0,
const char *TitleString = NULL)
{ {
char ErrorBuffer [B_PATH_NAME_LENGTH + 80 /* error message */ + 80]; char errorBuffer[2048];
if (TitleString == NULL) if (titleString == NULL)
TitleString = "Error Message:"; titleString = "Error Message:";
if (MessageString == NULL) if (messageString == NULL) {
{ if (errorNumber == B_OK)
if (ErrorNumber == 0) messageString = "No error, no message, why bother?";
MessageString = "No error, no message, why bother?"; else
else messageString = "Error";
MessageString = "Something went wrong"; }
}
if (ErrorNumber != 0) if (errorNumber != 0) {
{ snprintf(errorBuffer, sizeof(errorBuffer), "%s: %s (%lx)"
sprintf (ErrorBuffer, "%s, error code $%X/%d (%s) has occured.", "has occured.", messageString, strerror(errorNumber), errorNumber);
MessageString, ErrorNumber, ErrorNumber, strerror (ErrorNumber)); messageString = ErrorBuffer;
MessageString = ErrorBuffer; }
}
fputs (TitleString, stderr); fputs(titleString, stderr);
fputc ('\n', stderr); fputc('\n', stderr);
fputs (MessageString, stderr); fputs(messageString, stderr);
fputc ('\n', stderr); fputc('\n', stderr);
} }
/*! Determine if a line of text is the start of another message. Pine mailbox
/****************************************************************************** files have messages that start with a line that could say something like
* Determine if a line of text is the start of another message. Pine mailbox "From [email protected] Fri Oct 31 21:19:36 EST 1997" or maybe something
* files have messages that start with a line that could say something like like "From POPmail Mon Oct 20 21:12:36 1997" or in a more modern format,
* "From [email protected] Fri Oct 31 21:19:36 EST 1997" or maybe something "From [email protected] Tue Sep 4 09:04:11 2001 -0400". I generalise it
* like "From POPmail Mon Oct 20 21:12:36 1997" or in a more modern format, to "From blah Day MMM NN XX:XX:XX TZONE1 YYYY TZONE2". Blah is an e-mail
* "From [email protected] Tue Sep 4 09:04:11 2001 -0400". I generalise it address you can ignore (just treat it as a word separated by spaces). Day
* to "From blah Day MMM NN XX:XX:XX TZONE1 YYYY TZONE2". Blah is an e-mail is a 3 letter day of the week. MMM is a 3 letter month name. NN is the two
* address you can ignore (just treat it as a word separated by spaces). Day digit day of the week, has a leading space if the day is less than 10.
* is a 3 letter day of the week. MMM is a 3 letter month name. NN is the two XX:XX:XX is the time, the X's are digits. TZONE1 is the old style optional
* digit day of the week, has a leading space if the day is less than 10. time zone of 3 capital letters. YYYY is the four digit year. TZONE2 is the
* XX:XX:XX is the time, the X's are digits. TZONE1 is the old style optional optional modern time zone info, a plus or minus sign and 4 digits. Returns
* time zone of 3 capital letters. YYYY is the four digit year. TZONE2 is the true if the line of text (ended with a NUL byte, no line feed or carriage
* optional modern time zone info, a plus or minus sign and 4 digits. Returns returns at the end) is the start of a message.
* true if the line of text (ended with a NUL byte, no line feed or carriage */
* returns at the end) is the start of a message. bool
*/ IsStartOfMailMessage(char* lineString)
bool IsStartOfMailMessage (char *LineString)
{ {
char *StringPntr; // It starts with "From "
if (memcmp("From ", LineString, 5) != 0)
return false;
/* It starts with "From " */ char* string = lineString + 4;
while (*string == ' ')
string++;
if (memcmp ("From ", LineString, 5) != 0) // Skip over the e-mail address (or stop at the end of string).
return false;
StringPntr = LineString + 4;
while (*StringPntr == ' ')
StringPntr++;
/* Skip over the e-mail address (or stop at the end of string). */ while (*string != ' ' && *string != 0)
string++;
while (*string == ' ')
string++;
while (*StringPntr != ' ' && *StringPntr != 0) // TODO: improve this!!!
StringPntr++;
while (*StringPntr == ' ')
StringPntr++;
/* Look for the 3 letter day of the week. */ // Look for the 3 letter day of the week.
if (memcmp(string, "Mon", 3) != 0 && memcmp(string, "Tue", 3) != 0
&& memcmp(string, "Wed", 3) != 0 && memcmp(string, "Thu", 3) != 0
&& memcmp(string, "Fri", 3) != 0 && memcmp(string, "Sat", 3) != 0
&& memcmp(string, "Sun", 3) != 0) {
fprintf(stderr, "False alarm, not a valid day of the week in \"%s\""
".\n", lineString);
return false;
}
if (memcmp (StringPntr, "Mon", 3) != 0 && string += 3;
memcmp (StringPntr, "Tue", 3) != 0 && while (*string == ' ')
memcmp (StringPntr, "Wed", 3) != 0 && string++;
memcmp (StringPntr, "Thu", 3) != 0 &&
memcmp (StringPntr, "Fri", 3) != 0 &&
memcmp (StringPntr, "Sat", 3) != 0 &&
memcmp (StringPntr, "Sun", 3) != 0)
{
fprintf (stderr, "False alarm, not a valid day of the week in \"%s\".\n",
LineString);
return false;
}
StringPntr += 3;
while (*StringPntr == ' ')
StringPntr++;
/* Look for the 3 letter month code. */ // Look for the 3 letter month code.
if (memcmp(string, "Jan", 3) != 0 && memcmp(string, "Feb", 3) != 0
&& memcmp(string, "Mar", 3) != 0 && memcmp(string, "Apr", 3) != 0
&& memcmp(string, "May", 3) != 0 && memcmp(string, "Jun", 3) != 0
&& memcmp(string, "Jul", 3) != 0 && memcmp(string, "Aug", 3) != 0
&& memcmp(string, "Sep", 3) != 0 && memcmp(string, "Oct", 3) != 0
&& memcmp(string, "Nov", 3) != 0 && memcmp(string, "Dec", 3) != 0) {
fprintf(stderr, "False alarm, not a valid month name in \"%s\".\n",
lineString);
return false;
}
if (memcmp (StringPntr, "Jan", 3) != 0 && string += 3;
memcmp (StringPntr, "Feb", 3) != 0 && while (*string == ' ')
memcmp (StringPntr, "Mar", 3) != 0 && string++;
memcmp (StringPntr, "Apr", 3) != 0 &&
memcmp (StringPntr, "May", 3) != 0 &&
memcmp (StringPntr, "Jun", 3) != 0 &&
memcmp (StringPntr, "Jul", 3) != 0 &&
memcmp (StringPntr, "Aug", 3) != 0 &&
memcmp (StringPntr, "Sep", 3) != 0 &&
memcmp (StringPntr, "Oct", 3) != 0 &&
memcmp (StringPntr, "Nov", 3) != 0 &&
memcmp (StringPntr, "Dec", 3) != 0)
{
fprintf (stderr, "False alarm, not a valid month name in \"%s\".\n",
LineString);
return false;
}
StringPntr += 3;
while (*StringPntr == ' ')
StringPntr++;
/* Skip the day of the month. Require at least one digit. */ // Skip the day of the month. Require at least one digit.
if (*string < '0' || *string > '9') {
fprintf(stderr, "False alarm, not a valid day of the "
"month number in \"%s\".\n", lineString);
return false;
}
if (*StringPntr < '0' || *StringPntr > '9') while (*string >= '0' && *string <= '9')
{ string++;
fprintf (stderr, "False alarm, not a valid day of the " while (*string == ' ')
"month number in \"%s\".\n", LineString); string++;
return false;
}
while (*StringPntr >= '0' && *StringPntr <= '9')
StringPntr++;
while (*StringPntr == ' ')
StringPntr++;
/* Check the time. Look for the sequence // Check the time. Look for the sequence
digit-digit-colon-digit-digit-colon-digit-digit. */ // digit-digit-colon-digit-digit-colon-digit-digit.
if (StringPntr[0] < '0' || StringPntr[0] > '9' || if (string[0] < '0' || string[0] > '9'
StringPntr[1] < '0' || StringPntr[1] > '9' || || string[1] < '0' || string[1] > '9'
StringPntr[2] != ':' || || string[2] != ':'
StringPntr[3] < '0' || StringPntr[3] > '9' || || string[3] < '0' || string[3] > '9'
StringPntr[4] < '0' || StringPntr[4] > '9' || || string[4] < '0' || string[4] > '9'
StringPntr[5] != ':' || || string[5] != ':'
StringPntr[6] < '0' || StringPntr[6] > '9' || || string[6] < '0' || string[6] > '9'
StringPntr[7] < '0' || StringPntr[7] > '9') || string[7] < '0' || string[7] > '9') {
{ fprintf(stderr, "False alarm, not a valid time value in \"%s\".\n",
fprintf (stderr, "False alarm, not a valid time value in \"%s\".\n", lineString);
LineString); return false;
return false; }
}
StringPntr += 8;
while (*StringPntr == ' ')
StringPntr++;
/* Look for the optional antique 3 capital letter time zone and skip it. */ string += 8;
while (*string == ' ')
string++;
if (StringPntr[0] >= 'A' && StringPntr[0] <= 'Z' && // Look for the optional antique 3 capital letter time zone and skip it.
StringPntr[1] >= 'A' && StringPntr[1] <= 'Z' && if (string[0] >= 'A' && string[0] <= 'Z'
StringPntr[2] >= 'A' && StringPntr[2] <= 'Z') && string[1] >= 'A' && string[1] <= 'Z'
{ && string[2] >= 'A' && string[2] <= 'Z') {
StringPntr += 3; string += 3;
while (*StringPntr == ' ') while (*string == ' ')
StringPntr++; string++;
} }
/* Look for the 4 digit year. */ // Look for the 4 digit year.
if (string[0] < '0' || string[0] > '9'
|| string[1] < '0' || string[1] > '9'
|| string[2] < '0' || string[2] > '9'
|| string[3] < '0' || string[3] > '9') {
fprintf(stderr, "False alarm, not a valid 4 digit year in \"%s\".\n",
lineString);
return false;
}
if (StringPntr[0] < '0' || StringPntr[0] > '9' || string += 4;
StringPntr[1] < '0' || StringPntr[1] > '9' || while (*string == ' ')
StringPntr[2] < '0' || StringPntr[2] > '9' || string++;
StringPntr[3] < '0' || StringPntr[3] > '9')
{
fprintf (stderr, "False alarm, not a valid 4 digit year in \"%s\".\n",
LineString);
return false;
}
StringPntr += 4;
while (*StringPntr == ' ')
StringPntr++;
/* Look for the optional modern time zone and skip over it if present. */ // Look for the optional modern time zone and skip over it if present.
if ((string[0] == '+' || string[0] == '-')
&& string[1] >= '0' && string[1] <= '9'
&& string[2] >= '0' && string[2] <= '9'
&& string[3] >= '0' && string[3] <= '9'
&& string[4] >= '0' && string[4] <= '9') {
string += 5;
while (*string == ' ')
string++;
}
if ((StringPntr[0] == '+' || StringPntr[0] == '-') && // Look for end of string.
StringPntr[1] >= '0' && StringPntr[1] <= '9' && if (*string != 0) {
StringPntr[2] >= '0' && StringPntr[2] <= '9' && fprintf(stderr, "False alarm, extra stuff after the "
StringPntr[3] >= '0' && StringPntr[3] <= '9' && "year/time zone in \"%s\".\n", lineString);
StringPntr[4] >= '0' && StringPntr[4] <= '9') return false;
{ }
StringPntr += 5;
while (*StringPntr == ' ')
StringPntr++;
}
/* Look for end of string. */ return true;
if (*StringPntr != 0)
{
fprintf (stderr, "False alarm, extra stuff after the "
"year/time zone in \"%s\".\n", LineString);
return false;
}
return true;
} }
/*! Read the input file, convert it to mbox format, and write it to standard
/****************************************************************************** output. Returns zero if successful, a negative error code if an error
* Read the input file, convert it to mbox format, and write it to standard occured.
* output. Returns zero if successful, a negative error code if an error */
* occured. status_t
*/ ProcessMessageFile(char* fileName)
status_t ProcessMessageFile (char *FileName)
{ {
char ErrorMessage [B_PATH_NAME_LENGTH + 80]; fprintf(stdout, "Now processing: \"%s\"\n", fileName);
int i;
int InputFileDescriptor = -1;
FILE *InputFile = NULL;
int LineNumber;
BString MessageText;
status_t ReturnCode = -1;
char *StringPntr;
char TempString [102400];
time_t TimeValue;
fprintf (stderr, "Now processing: \"%s\"\n", FileName); FILE* inputFile = fopen(fileName, "rb");
if (inputFile == NULL) {
DisplayErrorMessage("Unable to open file", errno);
return errno;
}
/* Open the file. Try to open it in exclusive mode, so that it doesn't // Extract a text message from the Mail file.
accidentally open the output file, or any other already open file. */
InputFileDescriptor = open (FileName, O_RDONLY); status_t status = B_ERROR;
if (InputFileDescriptor < 0) BString messageText;
{ int lineNumber = 0;
ReturnCode = errno;
DisplayErrorMessage ("Unable to open file", ReturnCode);
return ReturnCode;
}
InputFile = fdopen (InputFileDescriptor, "rb");
if (InputFile == NULL)
{
ReturnCode = errno;
close (InputFileDescriptor);
DisplayErrorMessage ("fdopen failed to convert file handle to a "
"buffered file", ReturnCode);
return ReturnCode;
}
/* Extract a text message from the BeMail file. */ while (!feof(inputFile)) {
// First read in one line of text.
char line[102400];
if (fgets(line, sizeof(line), inputFile) == NULL) {
if (ferror(inputFile)) {
char errorString[2048];
snprintf(errorString, sizeof(errorString),
"Error while reading from \"%s\"", fileName);
DisplayErrorMessage(errorString, errno);
status = errno;
goto out;
}
break;
// No error, just end of file.
}
LineNumber = 0; // Remove any trailing control characters (line feed usually, or CRLF).
while (!feof (InputFile)) // Might also nuke trailing tabs too. Doesn't usually matter. The main
{ // thing is to allow input files with both LF and CRLF endings (and
/* First read in one line of text. */ // even CR endings if you come from the Macintosh world).
if (!fgets (TempString, sizeof (TempString), InputFile)) char* string = line + strlen(line) - 1;
{ while (string >= line && *string < 32)
ReturnCode = errno; string--;
if (ferror (InputFile)) *(++string) = 0;
{
sprintf (ErrorMessage,
"Error while reading from \"%s\"", FileName);
DisplayErrorMessage (ErrorMessage, ReturnCode);
goto ErrorExit;
}
break; /* No error, just end of file. */
}
/* Remove any trailing control characters (line feed usually, or CRLF). if (lineNumber == 0 && line[0] == 0) {
Might also nuke trailing tabs too. Doesn't usually matter. The main thing // Skip leading blank lines.
is to allow input files with both LF and CRLF endings (and even CR endings continue;
if you come from the Macintosh world). */ }
lineNumber++;
StringPntr = TempString + strlen (TempString) - 1; // Prepend the new mbox message header, if the first line of the message
while (StringPntr >= TempString && *StringPntr < 32) // doesn't already have one.
StringPntr--; if (lineNumber == 1 && !IsStartOfMailMessage(line)) {
*(++StringPntr) = 0; time_t timestamp = gDateStampTime++;
messageText.Append("From [email protected] ");
messageText.Append(ctime(&timestamp));
}
if (LineNumber == 0 && TempString[0] == 0) // Append the line to the current message text.
continue; /* Skip leading blank lines. */ messageText.Append(line);
LineNumber++; messageText.Append("\n");
}
/* Prepend the new mbox message header, if the first line of the message // Remove blank lines from the end of the message (a pet peeve of mine), but
doesn't already have one. */ // end the message with two new lines to separate it from the next message.
int i = messageText.Length();
while (i > 0 && (messageText[i - 1] == '\n' || messageText[i - 1] == '\r'))
i--;
messageText.Truncate(i);
messageText.Append("\n\n");
if (LineNumber == 1 && !IsStartOfMailMessage (TempString)) // Write the message out.
{ if (puts(messageText.String()) < 0) {
TimeValue = DateStampTime++; DisplayErrorMessage ("Error while writing the message", errno);
MessageText.Append ("From [email protected] "); status = errno;
MessageText.Append (ctime (&TimeValue)); } else
} status = B_OK;
/* Append the line to the current message text. */ out:
fclose(inputFile);
MessageText.Append (TempString); return status;
MessageText.Append ("\n");
}
/* Remove blank lines from the end of the message (a pet peeve of mine), but
end the message with two new lines to separate it from the next message. */
i = MessageText.Length ();
while (i > 0 && (MessageText[i-1] == '\n' || MessageText[i-1] == '\r'))
i--;
MessageText.Truncate (i);
MessageText.Append ("\n\n");
/* Write the message out. */
if (puts (MessageText.String()) < 0)
{
ReturnCode = errno;
DisplayErrorMessage ("Error while writing the message", ReturnCode);
goto ErrorExit;
}
ReturnCode = 0;
ErrorExit:
fclose (InputFile);
return ReturnCode;
} }
int main (int argc, char** argv) int
main(int argc, char** argv)
{ {
dirent_t *DirEntPntr; BApplication app("application/x-vnd.Haiku-mail2mbox");
DIR *DirHandle;
status_t ErrorCode;
char InputPathName [B_PATH_NAME_LENGTH];
int MessagesDoneCount = 0;
BApplication MyApp ("application/x-vnd.agmsmith.bemailtombox");
const char *StringPntr;
char TempString [1024 + 256];
if (argc <= 1 || argc >= 3) if (argc <= 1 || argc >= 3) {
{ printf("%s is a utility for converting BeMail e-mail\n", argv[0]);
printf ("%s is a utility for converting BeMail e-mail\n", argv[0]); printf("files to Unix Pine style e-mail files. It could well\n");
printf ("files to Unix Pine style e-mail files. It could well\n"); printf("work with other Unix style mailbox files. Each message in\n");
printf ("work with other Unix style mailbox files. Each message in\n"); printf("the input directory is converted and sent to the standard\n");
printf ("the input directory is converted and sent to the standard\n"); printf("output. Usage:\n\n");
printf ("output. Usage:\n\n"); printf("%s InputDirectory >OutputFile\n\n", kProgramName);
printf ("%s InputDirectory >OutputFile\n\n", kProgramName); printf("Public domain, by Alexander G. M. Smith.\n");
printf ("Public domain, by Alexander G. M. Smith.\n"); return -10;
return -10; }
}
/* Set the date stamp to the current time. */ // Set the date stamp to the current time.
gDateStampTime = time (NULL);
DateStampTime = time (NULL); // Try to open the input directory.
char inputPathName[B_PATH_NAME_LENGTH];
strlcpy(inputPathName, argv[1], sizeof(inputPathName) - 2);
/* Try to open the input directory. */ char tempString[2048];
memset (InputPathName, 0, sizeof (InputPathName)); DIR* dir = opendir(inputPathName);
strncpy (InputPathName, argv[1], sizeof (InputPathName) - 2); if (dir == NULL) {
DirHandle = opendir (InputPathName); sprintf(tempString, "Problems opening directory named \"%s\".",
if (DirHandle == NULL) inputPathName);
{ DisplayErrorMessage(tempString, errno);
ErrorCode = errno; return 1;
sprintf (TempString, "Problems opening directory named \"%s\".", }
InputPathName);
DisplayErrorMessage (TempString, ErrorCode);
return ErrorCode;
}
/* Append a trailing slash to the directory name, if it needs one. */ // Append a trailing slash to the directory name, if it needs one.
if (inputPathName[strlen(InputPathName) - 1] != '/')
strcat(inputPathName, "/");
if (InputPathName [strlen (InputPathName) - 1] != '/') int messagesDoneCount = 0;
strcat (InputPathName, "/"); status_t status = B_OK;
ErrorCode = 0; while (dirent_t* entry = readdir(dir)) {
while (ErrorCode == 0 && (DirEntPntr = readdir (DirHandle)) != NULL) // skip '.' and '..'
{ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
for (StringPntr = DirEntPntr->d_name; *StringPntr != 0; StringPntr++) break;
if (*StringPntr != '.')
break;
if (*StringPntr == 0)
continue; /* Skip all period names, like . or .. or ... etc. */
strcpy (TempString, InputPathName); strlcpy(tempString, inputPathName, sizeof(tempString));
strcat (TempString, DirEntPntr->d_name); strlcat(tempString, entry->d_name, , sizeof(tempString));
ErrorCode = ProcessMessageFile (TempString);
MessagesDoneCount++;
}
closedir (DirHandle);
if (ErrorCode != 0)
{
DisplayErrorMessage ("Stopping early because an error occured", ErrorCode);
return ErrorCode;
}
fprintf (stderr, "Did %d messages successfully.\n", MessagesDoneCount); status = ProcessMessageFile(tempString);
return 0; if (status != B_OK)
break;
messagesDoneCount++;
}
closedir(dir);
if (status != B_OK) {
DisplayErrorMessage("Stopping early because an error occured", status);
return ErrorCode;
}
fprintf(stderr, "Did %d messages successfully.\n", messagesDoneCount);
return 0;
} }