int main(int argc, char* argv[]) { BApplication mailApp(APP_SIG); // No arguments, show usage if (argc < 2) { fprintf(stdout,"This program can only send mail, not read it.\n"); fprintf(stdout,"usage: %s [-v] [-s subject] [-c cc-addr] " "[-b bcc-addr] to-addr ...\n", argv[0]); return 0; } char *subject = "No subject"; char *cc = ""; char *bcc = ""; BString to; bool verbose = false; // Parse arguments for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-v") == 0) verbose = true; else if (strcmp(argv[i], "-s") == 0) { subject = argv[i+1]; i++; } else if (strcmp(argv[i], "-c") == 0) { cc = argv[i+1]; i++; } else if (strcmp(argv[i], "-b") == 0) { bcc = argv[i+1]; i++; } else { if (to.Length() > 0) to.Append(", "); to.Append(argv[i]); } } if (verbose) { fprintf(stdout, "\n"); fprintf(stdout, "To:\t%s\n", to.String()); fprintf(stdout, "Cc:\t%s\n", cc); fprintf(stdout, "Bcc:\t%s\n", bcc); fprintf(stdout, "Subj:\t%s\n", subject); fprintf(stdout, "\n"); } // Check if recipients are valid if (strcmp(to.String(), "") == 0 && strcmp(cc, "") == 0 && strcmp(bcc, "") == 0) { fprintf(stderr, "[Error]: You must specify at least one recipient " "in to, cc or bcc fields.\n"); return -1; } bool isTerminal = isatty(STDIN_FILENO) != 0; if (isTerminal) { fprintf(stderr, "Now type your message.\n" "Type '.' alone on a line to end your text and send it.\n"); } BString body; char line[32768] = ""; // Read each line and collect the body text until we get an end of text // marker. That's a single dot "." on a line typed in by the user, // or end of file when reading a file. do { if (fgets(line, sizeof(line), stdin) == NULL) { // End of file or an error happened, just send collected body text. break; } if (isTerminal && strcmp(line, ".\n") == 0) break; body.Append(line); } while (true); if (verbose) fprintf(stdout, "\nBody:\n%s\n", body.String()); if (verbose) fprintf(stderr, "Sending E-mail...\n"); fflush(stdout); BMailMessage mail; mail.AddHeaderField(B_MAIL_TO, to.String()); mail.AddHeaderField(B_MAIL_CC, cc); mail.AddHeaderField(B_MAIL_BCC, bcc); mail.AddHeaderField(B_MAIL_SUBJECT, subject); mail.AddContent(body.String(), body.Length()); status_t result = mail.Send(); if (result == B_OK) { if (verbose) fprintf(stderr, "Message was sent successfully.\n"); return 0; } fprintf(stderr, "Message failed to send: %s\n", strerror(result)); return result; }
bool MailingList::DistributeEmail(IncomingMail* ICMail, std::string ogaddrfilepath) { //send ICMail to every address in ogaddrfilepath std::vector<std::string> recipients; BFile recipientlistbfile; status_t filestatus=recipientlistbfile.SetTo(ogaddrfilepath.c_str(),B_READ_ONLY); if (filestatus!=B_NO_ERROR) { LogError("ERROR: Could not read temp file from authentication program - the file could not be opened. Does it exist?"); return false; } off_t bytes; //size of file if (recipientlistbfile.GetSize(&bytes) == B_NO_ERROR) { char* buff = new char[bytes]; off_t bytesread=recipientlistbfile.Read(buff,bytes); if (bytesread > 0) { //file read ok std::string addr=""; for (int x=0; x < bytesread; x++) { if (buff[x]!='\n') { addr=addr+buff[x]; } else { recipients.push_back(addr); addr=""; } } delete buff; } else { LogError("ERROR: Could not read temp file from authentication program - the file was empty"); delete buff; return false; } } else { LogError("ERROR: Could not read temp file from authentication program -- could not determine file size"); return false; } ICMail->AddSubjectPrefix(fListSubjectPrefix); //fListSubjectPrefix will be null str if not defined in conf file ICMail->CleanHeaders(); //clean & setup headers ready for sending message out to recipients ICMail->AdjustReplyTo(fForceReplyToList); //set reply to to either sender or list IC address //if List-Xyz header values were set in conf file we need to set them in msg if (fListOwner!="") { ICMail->SetListOwnerHeader(fListOwner); } if (fListHelp!="") { ICMail->SetListHelpHeader(fListHelp); } if (fListArchive!="") { ICMail->SetListArchiveHeader(fListArchive); } if (fListSubscribe!="") { ICMail->SetListSubscribeHeader(fListSubscribe); } if (fListUnSubscribe!="") { ICMail->SetListUnSubscribeHeader(fListUnSubscribe); } //call GetFromField to get email address in case we need to bounce msg std::string ICsendersAddrField=ICMail->GetSendersAddr(); //returns null string if unable to find //at present ICsendersAddrField now has address in form user@domain NOT <user@domain> is this in line with RFC spec? if (ICMail->CheckIfPlainTextCriteriaPassed(fPlainTextOnly)==false) { //bounce if (fPlainTextOnly=='Y') { //bounce to sender LogError("INFO: Incoming email not text/plain and non plain text messages are not allowed. Bounced to "+ICsendersAddrField); BMailMessage* ogmail; ogmail= new BMailMessage(); ogmail->AddHeaderField(B_MAIL_TO,ICsendersAddrField.c_str()); ogmail->AddHeaderField(B_MAIL_FROM,fListOGEnvelopeAddressFromAddress.c_str()); std::string bouncesubject=std::string("Undelivered mail: Your message to "); bouncesubject=bouncesubject+fListName+" was rejected"; ogmail->AddHeaderField(B_MAIL_SUBJECT,bouncesubject.c_str()); std::string xmailer=(fApp->GetAppName())+" mailing list server for Haiku"; ogmail->AddHeaderField("X-Mailer: ",xmailer.c_str()); ogmail->AddHeaderField("precedence: ","list"); std::string bouncecontent="Your message to "+fListName+" was rejected because this list only accepts plain text messages. Make sure your email program is not creating HTML or Rich Text emails and that there are no attached files."; bouncecontent=bouncecontent+"\n\nThis is an automated reply sent from the "+fApp->GetAppName()+" for Haiku server at "+fListICAddress; ogmail->AddContent(bouncecontent.c_str(),strlen(bouncecontent.c_str())); ogmail->Send(); delete ogmail; } else { //fPlainTextOnly must be 'H' //bounce to sender LogError("INFO: Incoming email not HTML or plain text and non text messages are not allowed. Bounced to "+ICsendersAddrField); BMailMessage* ogmail; ogmail= new BMailMessage(); ogmail->AddHeaderField(B_MAIL_TO,ICsendersAddrField.c_str()); ogmail->AddHeaderField(B_MAIL_FROM,fListOGEnvelopeAddressFromAddress.c_str()); std::string bouncesubject=std::string("Undelivered mail: Your message to "); bouncesubject=bouncesubject+fListName+" was rejected"; ogmail->AddHeaderField(B_MAIL_SUBJECT,bouncesubject.c_str()); std::string xmailer=(fApp->GetAppName())+" mailing list server for Haiku"; ogmail->AddHeaderField("X-Mailer: ",xmailer.c_str()); ogmail->AddHeaderField("precedence: ","list"); std::string bouncecontent="Your message to "+fListName+" was rejected because this list only accepts HTML or plain text messages. Make sure that there are no attached files."; bouncecontent=bouncecontent+"\n\nThis is an automated reply sent from the "+fApp->GetAppName()+" for Haiku server at "+fListICAddress; ogmail->AddContent(bouncecontent.c_str(),strlen(bouncecontent.c_str())); ogmail->Send(); delete ogmail; } return true; } if (ICMail->GetICFileSize() > fMaxContentBytes) { //msg too big bounce to sender LogError("INFO: Incoming email too big. Bounced to "+ICsendersAddrField); BMailMessage* ogmail; ogmail= new BMailMessage(); ogmail->AddHeaderField(B_MAIL_TO,ICsendersAddrField.c_str()); ogmail->AddHeaderField(B_MAIL_FROM,fListOGEnvelopeAddressFromAddress.c_str()); std::string bouncesubject=std::string("Undelivered mail: Your message to "); bouncesubject=bouncesubject+fListName+" was rejected"; ogmail->AddHeaderField(B_MAIL_SUBJECT,bouncesubject.c_str()); std::string xmailer=(fApp->GetAppName())+" mailing list server for Haiku"; ogmail->AddHeaderField("X-Mailer: ",xmailer.c_str()); ogmail->AddHeaderField("precedence: ","list"); stringstream converter; converter << fMaxContentBytes << " bytes, your message was " << ICMail->GetICFileSize() << " bytes"; std::string toobigcontent="Your message to "+fListName+" is too big and was rejected. Maximum allowable size for this list is "+converter.str(); toobigcontent=toobigcontent+"\n\nThis is an automated reply sent from the "+fApp->GetAppName()+" for Haiku server at "+fListICAddress; ogmail->AddContent(toobigcontent.c_str(),strlen(toobigcontent.c_str())); ogmail->Send(); delete ogmail; return true; } //setup a temp file to store the modified og msg std::stringstream epochsecs; epochsecs << real_time_clock(); //secs now since unix epoch int filenamecounterInt=0; //will be incremented until we get a unique filename string bool nonuniquefilename=true; BEntry tempFileBEntry; std::string tempFilePath; BFile* tempFileBFile = new BFile(); do { filenamecounterInt++; std::stringstream filenamecounter; filenamecounter << filenamecounterInt; tempFilePath=fApp->GetTempDirPath()+fListICAddress+"--"+epochsecs.str()+filenamecounter.str(); //test if tempFilePath already exists tempFileBEntry.SetTo(tempFilePath.c_str()); status_t tempFileResult=tempFileBFile->SetTo(&tempFileBEntry,B_READ_WRITE|B_FAIL_IF_EXISTS|B_CREATE_FILE); //fails if already exists if (tempFileResult==B_FILE_EXISTS) { nonuniquefilename=true; } else if (tempFileResult==B_NO_ERROR) { nonuniquefilename=false; } else { //error LogError("ERROR: Could not create temp file to store outgoing email"); return false; } }while(nonuniquefilename); //Write modified msg into temp file ICMail->WriteToFile(tempFileBFile); //store senders addr so we can log it later std::string sender=""; //Send out modified msg in temp file to all recipients for (int x=0; x< recipients.size(); x++) { std::string recipient=recipients[x]; BEmailMessage* ogmail; ogmail= new BEmailMessage(tempFileBFile); ogmail->SetTo(recipient.c_str()); sender=std::string(ogmail->From()); //1st version of send indicates whether to change the From: field to the specified account (requires modified mailkit) ogmail->SendViaAccountWithFromPreset(fListOGEnvelopeAddressFromAddress.c_str()); //ogmail->SendViaAccount(fListOGEnvelopeAddressFromAddress.c_str()); ogmail->Send(true); delete ogmail; } tempFileBFile->Unset(); //close file delete tempFileBFile; //delete obj //archive msg if needed bool archived=false; if (fArchivePath!="") { BDirectory dir; if ( dir.SetTo(fArchivePath.c_str()) !=B_OK ) { LogError("ERROR: Could not archive message. Check archive folder exists and is writable"); } else { if ( tempFileBEntry.MoveTo(&dir) !=B_NO_ERROR) { LogError("ERROR: Could not archive message. Check archive folder exists and is writable"); } else { archived=true; } } } if (archived==false) { //if archived then the file was moved so we dont need to delete the original tempFileBEntry.Remove();//remove file from filesystem } stringstream numRecipients; numRecipients << recipients.size(); if ( (fLogSuccesses) && (recipients.size()>0) ) { //if we recipients.size() was 0 sender var is null str as its set in the distribution loop LogError("INFO: Successfully distributed an email to "+numRecipients.str()+" recipients from "+sender); } return true; }
int main(int argc, char* argv[]) { BApplication mailApp(APP_SIG); // No arguments, show usage if (argc < 2) { fprintf(stdout,"This program can only send mail, not read it.\n"); fprintf(stdout,"usage: %s [-v] [-s subject] [-c cc-addr] " "[-b bcc-addr] to-addr ...\n", argv[0]); fflush(stdout); return 0; } char *subject = "No title"; char *cc = ""; char *bcc = ""; BString to = ""; BString body = ""; bool verbose =false; // Parse arguments for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-v") == 0) verbose = true; else if (strcmp(argv[i], "-s") == 0) { subject = argv[i+1]; i++; } else if (strcmp(argv[i], "-c") == 0) { cc = argv[i+1]; i++; } else if (strcmp(argv[i], "-b") == 0) { bcc = argv[i+1]; i++; } else { to.Append(argv[i]); if (i < argc - 1) to.Append(" "); } } if (verbose) { fprintf(stdout, "\n"); fprintf(stdout, "To:\t<%s> \n", to.String()); fprintf(stdout, "Cc:\t<%s> \n", cc); fprintf(stdout, "Bcc:\t<%s> \n", bcc); fprintf(stdout, "Subj:\t<%s> \n", subject); fprintf(stdout, "Body:\t<%s> \n", body.String()); fprintf(stdout, "\n"); } // Check if recipients are valid if (strcmp(to.String(), "") == 0 && strcmp(cc, "") == 0 && strcmp(bcc, "") == 0) { fprintf(stdout, "[Error]: You must specify at least one recipient " "in to, cc or bcc fields.\n"); return -1; } // Read each line until we get a single dot "." on a line char line[32768] = ""; printf("Now type your message.\nType '.' alone on a line to send it.\n"); do { gets(line); if (strcmp(line, ".") != 0) { body.Append(line).Append("\n"); } // fprintf(stdout,"Line: %s \n",line); } while (strcmp(line, ".") != 0); if (verbose) fprintf(stdout, "\nBody:\n%s\n", body.String()); if (verbose) fprintf(stdout, "\nSending E-mail...\n"); fflush(stdout); BMailMessage mail; mail.AddHeaderField(B_MAIL_TO, to.String()); mail.AddHeaderField(B_MAIL_CC, cc); mail.AddHeaderField(B_MAIL_BCC, bcc); mail.AddHeaderField(B_MAIL_SUBJECT, subject); mail.AddContent(body.String(), strlen(body.String())); status_t result = mail.Send(); if (result == B_OK) { fprintf(stdout, "\nMessage was sent successfully.\n"); return 0; } fprintf(stdout, "Message failed to send: %s", strerror(result)); return result; }
bool MailingList::ProcessEmailFile(std::string emailfilepathstr) { /* Check if sender of email is authorised to post to this list, if not return true and caller will delete file else copy it to an outgoing email with relevent header changes, queue og mail for delivery and return true so caller will delete file. Any errors return false */ BFile* bfile = new BFile(emailfilepathstr.c_str(),B_READ_WRITE); if (bfile->InitCheck() != B_NO_ERROR) { LogError("ERROR: Could not process an incoming email. BFile::InitCheck was false"); return false; } IncomingMail* ICMail= new IncomingMail(bfile,this); if (ICMail->InitCheck()==false) { LogError("ERROR: Could not process an incoming email. File read failed. IncomingMail::InitCheck was false"); return false; } if (fLogSuccesses) { LogError("INFO: Processing an email file from "+ICMail->GetSendersAddr()); } int32 authstatus=1; /* Return vals from external auth prog are 0=Authorised 1=Error 2=Not Authorsed - bounce msg 3=Not Authorised - silently discard This func should return false if val is 1, thus ensuring the incoming file is not deleted and will be re-processed later for all other values it should return true, indicating that the incoming file can be deleted */ int32 arg_c = 4; //no of args passed in arg_v extern char **environ; //env variables char **arg_v; arg_v = (char **) malloc(sizeof(char*) * (arg_c+1)); //array must hold arg_c elements + a terminating null std::stringstream epochsecs; epochsecs << real_time_clock(); //secs now since unix epoch int filenamecounterInt=0; //will be incremented until we get a unique filename string bool nonuniquefilename=true; BEntry tempFileBEntry; std::string tempFilePath; do { filenamecounterInt++; std::stringstream filenamecounter; filenamecounter << filenamecounterInt; MailMistressApplication* app=(MailMistressApplication*) be_app; tempFilePath=app->GetTempDirPath()+fListICAddress+"--"+ICMail->GetSendersAddr()+"--"+epochsecs.str()+filenamecounter.str(); //test if tempFilePath already exists tempFileBEntry.SetTo(tempFilePath.c_str()); BFile tempFileBFile; status_t tempFileResult=tempFileBFile.SetTo(&tempFileBEntry,B_READ_WRITE|B_FAIL_IF_EXISTS|B_CREATE_FILE); //fails if already exists if (tempFileResult==B_FILE_EXISTS) { nonuniquefilename=true; } else if (tempFileResult==B_NO_ERROR) { nonuniquefilename=false; tempFileBFile.Unset(); //close file } else { //error bfile->Unset(); //delete ICMail obj delete ICMail; delete bfile; return false; } }while(nonuniquefilename); arg_v[0]=strdup(fAuthProgPath.c_str()); //path to exe arg_v[1]=strdup((ICMail->GetSendersAddr()).c_str()); //senders email addr arg_v[2]=strdup(tempFilePath.c_str()); //path to temp file arg_v[3]=strdup(fListICAddress.c_str()); //list IC address arg_v[4]=NULL; thread_id authprog_team; authprog_team=load_image(arg_c,(const char**)arg_v,(const char**)environ); free(arg_v); wait_for_thread(authprog_team,&authstatus); //if authstatus==0 then temp file will now contain all recipient email addresses one per line if (authstatus==0) { //send to recipients in temp file if (DistributeEmail(ICMail,tempFilePath)) { //delete temp file tempFileBEntry.Remove(); //delete ICMail obj delete ICMail; //close orig email file bfile->Unset(); delete bfile; return true; } else { //delete temp file tempFileBEntry.Remove(); //delete ICMail obj delete ICMail; //close orig email file bfile->Unset(); delete bfile; return false; } } else if (authstatus==2) { LogError("INFO: Auth status 2 -- Bouncing to "+ICMail->GetSendersAddr()); BMailMessage* ogmail; ogmail= new BMailMessage(); ogmail->AddHeaderField(B_MAIL_TO,(ICMail->GetSendersAddr()).c_str()); ogmail->AddHeaderField(B_MAIL_FROM,fListOGEnvelopeAddressFromAddress.c_str()); std::string bouncesubject=std::string("Undelivered mail: Your message to "); bouncesubject=bouncesubject+fListName+" was rejected"; ogmail->AddHeaderField(B_MAIL_SUBJECT,bouncesubject.c_str()); ogmail->AddHeaderField("X-Mailer: ",(fApp->GetAppName()).c_str()); ogmail->AddContent(fUnauthorisedBounceMsgContents.c_str(),strlen(fUnauthorisedBounceMsgContents.c_str())); ogmail->Send(); delete ogmail; } else if (authstatus==3) { LogError("INFO: Auth status 3 -- Silently discarding email from "+ICMail->GetSendersAddr()); } //delete temp file tempFileBEntry.Remove(); if ( (authstatus==2) || (authstatus==3) ) { //ok so return true to delete incoming file delete ICMail; bfile->Unset(); delete bfile; return true; } else { //error occured so return false and incoming file will be kept for reprocessing later LogError("ERROR: Auth status 1 (or other error value). Either the autentication program failed to run or it encountered an error itself"); delete ICMail; bfile->Unset(); delete bfile; return false; } }