#include #include #include #include #include #include #include #include "framework.h" #include "tlmpmail.h" #include "tlmpmail.m" enum COMPOSE_CMD { COMPOSE_NONE, COMPOSE_NEW, COMPOSE_FORWARD, COMPOSE_REPLY, COMPOSE_RESUME }; struct MAIL_COMPOSE_PRIVATE { EMAILADDRS to; EMAILADDRS cc; EMAILADDRS bcc; bool framework_active; PRIVATE_MESSAGE wakeup; MAIL_MESSAGE *msg; COMPOSE_CMD cmd; }; void _F_MAIL_COMPOSE::archive(void *, MAIL_MESSAGE_FULL &, const ATTACHEMENTS &attachs) { } void _F_MAIL_COMPOSE::cancel(void *, MAIL_MESSAGE_FULL &) { } PUBLIC MAIL_COMPOSE::MAIL_COMPOSE (_F_MAIL_COMPOSE &_c) : c(_c) { priv = new MAIL_COMPOSE_PRIVATE; priv->framework_active = false; priv->msg = NULL; priv->cmd = COMPOSE_NONE; } struct COMPOSE_EDIT{ SSTRING to,bcc,cc; }; static void compose_saveedit ( MAIL_MESSAGE_FULL &newmsg, COMPOSE_EDIT &edit) { newmsg.to.remove_all(); newmsg.to.parse (edit.to.get()); newmsg.cc.remove_all(); newmsg.cc.parse (edit.cc.get()); newmsg.bcc.remove_all(); newmsg.bcc.parse (edit.bcc.get()); } /* Insert a text file in the edit buffer of a current message */ static void compose_insert (SSTRING &text) { SSTRING *text; glocal.text = &text; DIALOG dia; dia.settype (DIATYPE_POPUP); SSTRING file; dia.newf_str (MSG_U(F_NAME,"File name/path"),file); int nof = 0; while (1){ MENU_STATUS code = dia.edit (MSG_U(T_INSERT,"Insert a file"),"" ,help_nil,nof); if (code == MENU_ESCAPE || code == MENU_CANCEL){ break; }else{ int ok = (file.get(),false); glocal.text->append (line); return 0; if (ok != -1) break; } } } /* Initialise the edit buffer with a quoted copy of the message */ void compose_quote( MAIL_MESSAGE_FULL &msg, SSTRING &txt, const char *prefix) { glocal SSTRING *txt = &txt; glocal const char *prefix = prefix; (msg,true,true); const char *pt = info.body; const char *start = pt; while (*pt != '\0'){ if (*pt == '\n'){ int len = (int)(pt - start)+1; glocal.txt->append (glocal.prefix); glocal.txt->append (start,len); start = pt+1; } pt++; } if (pt > start) glocal.txt->appendf ("%s%s",glocal.prefix,start); } /* Initialise the edit buffer with a quoted copy of the message */ void compose_quotereply( MAIL_MESSAGE_FULL &msg, SSTRING &txt, const char *prefix) { SSTRING datestr; miscmail_formatdate (msg.date,datestr); txt.appendf (MSG_U(I_WROTE,"On %s, %s wrote\n"),datestr.get() ,msg.get_from()); compose_quote (msg,txt,prefix); } /* Initialise the edit buffer with a quoted copy of the message */ void _F_MAIL_COMPOSE::quotereply(MAIL_MESSAGE_FULL &msg, SSTRING &txt) { compose_quotereply (msg,txt,"> "); initnewmsg (txt); } /* Initialise the text buffer with the quoted message to forward */ void _F_MAIL_COMPOSE::quoteforward(MAIL_MESSAGE_FULL &msg, SSTRING &txt) { initnewmsg(txt); if (!txt.is_empty()) txt.append ("\n"); txt.appendf ("%s\n",MSG_U(I_FORWARDLINE,"----Forward message----")); SSTRING datestr; miscmail_formatdate (msg.date,datestr); txt.appendf ("Date: %s\n",datestr.get()); txt.appendf ("From: %s <%s>\n",msg.get_from(),msg.getemail_from()); txt.appendf ("To: %s\n",msg.get_to()); txt.appendf ("Subject: %s\n\n",msg.getsubject()); compose_quote (msg,txt,""); } void _F_MAIL_COMPOSE::initnewmsg (SSTRING &txt) { SSTRING *txt; glocal.txt = &txt; const char *home = getenv ("HOME"); if (home != NULL){ char path[PATH_MAX]; snprintf (path,sizeof(path)-1,"%s/.signature",home); (path,false); // Nothing to do, we don't care glocal.txt->append ("\n"); glocal.txt->append (line); return 0; } } void _F_MAIL_COMPOSE::addrbook (EMAILADDRS &) { } void _F_MAIL_COMPOSE::folderlist (SSTRING &) { } /* Insert new fields and button in the composition dialog Return the MENUBUT_xxx mask of the added buttons. */ void *_F_MAIL_COMPOSE::codialog_setup (DIALOG &, int &) { return NULL; } /* Process the buttons and the messages added by codialog */ void _F_MAIL_COMPOSE::codialog_buttons (void *, DIALOG &, MENU_STATUS) { } /* Tell the codialog to clean up */ void _F_MAIL_COMPOSE::codialog_end (void *) { } /* Validate the extra fields entered by codialog Return -1 if any error, set the field number to point on the offending field. */ int _F_MAIL_COMPOSE::codialog_validate (void * , DIALOG &, int &) { return 0; } /* Send the message to the outbox, return -1 if any error */ int _F_MAIL_COMPOSE::outbox (void *, MAIL_MESSAGE_FULL &, const ATTACHEMENTS &) { xconf_notice (MSG_U(N_NOOUTBOX,"No outbox functionality implemented yet!")); return -1; } /* Should perform completion of the email address */ int _F_MAIL_COMPOSE::complete(const char *, EMAILADDRS &) { return 0; // Trick to tell the caller that the client did not // implemented the complete functag } /* Let the user pick a file to attach. Return -1 if nothing was picked. */ int _F_MAIL_COMPOSE::editattach(ATTACHEMENTS &attachs) { xconf_notice (MSG_U(E_NOTDONE,"Not implemented yet")); return -1; } /* Trigger the address book and append the selected email addresses to a given field */ static void compose_appendaddrs( _F_MAIL_COMPOSE *c, DIALOG &dia, SSTRING &f, // Append the emails there int fieldnum) // Field to reload { EMAILADDRS addrs; if (f.is_filled() && f.strchr('@')==NULL){ // We try completion from the address book int ok = c->complete (f.get(),addrs); if (ok == 0){ c->addrbook (addrs); }else if (ok > 0){ f.setempty(); } }else{ c->addrbook (addrs); } if (addrs.is_filled()){ SSTRING tmp; addrs.format (tmp); if (!f.is_empty()) f.append (" ,"); f.append (tmp); dia.reload (fieldnum); } } /* Start the interactive framework */ PUBLIC void MAIL_COMPOSE::start_framework () { _F_MAIL_COMPOSE *c; MAIL_COMPOSE_PRIVATE *priv; glocal.c = &c; glocal.priv = priv; priv->framework_active = true; (MSG_U(T_MSGCOMPOSER,"Message viewer"),priv->wakeup); newdocument(); DIALOG dia; info.msgs.waitfor (dia); //dia.gui_group (""); MAIL_MESSAGE *msg = glocal.priv->msg; MAIL_MESSAGE_FULL orig; ATTACHEMENTS attachs; if (msg != NULL){ msg->incrusage(); msg->loadmsg(orig); } MAIL_MESSAGE_FULL newmsg; SSTRING title; if (glocal.priv->cmd == COMPOSE_REPLY){ newmsg.to = glocal.priv->to; newmsg.cc = glocal.priv->cc; newmsg.bcc = glocal.priv->bcc; newmsg.id = msg->id; const char *orig_subject = orig.getsubject(); // Insert the re: prefix if not already there if (strncasecmp(orig_subject,MSG_U(I_REPLYPREFIX,"re:") ,strlen(MSG_R(I_REPLYPREFIX)))==0){ newmsg.subject.setfrom (orig_subject); }else{ newmsg.subject.setfromf ("%s %s",MSG_R(I_REPLYPREFIX) ,orig_subject); } title.setfromf (MSG_U(T_REPLY,"Reply to %s"),orig.get_from()); glocal.c->quotereply(orig,newmsg.text); }else if (glocal.priv->cmd == COMPOSE_FORWARD){ newmsg.subject.setfromf ("fw: %s",orig.subject.get()); title.setfrom (MSG_U(T_FORWARD,"Forward message")); glocal.c->quoteforward (orig,newmsg.text); }else if (glocal.priv->cmd == COMPOSE_RESUME){ newmsg.to = orig.to; newmsg.cc = orig.cc; newmsg.bcc = orig.bcc; newmsg.fcc = orig.fcc; newmsg.subject = orig.subject; newmsg.text = orig.text; }else{ title.setfrom (MSG_U(T_COMPOSE,"New message")); glocal.c->initnewmsg (newmsg.text); newmsg.to = glocal.priv->to; newmsg.cc = glocal.priv->cc; newmsg.bcc = glocal.priv->bcc; } COMPOSE_EDIT edit; newmsg.to.format (edit.to); newmsg.cc.format (edit.cc); newmsg.bcc.format (edit.bcc); mime_translate (edit.to); mime_translate (edit.cc); mime_translate (edit.bcc); mime_translate (newmsg.subject); dia.gui_group (""); int field_to = dia.getnb(); dia.newf_str (MSG_U(F_TO,"To"),edit.to,65); PRIVATE_MESSAGE p_to,p_cc,p_bcc,p_folder,p_attach; dia.set_helpdia (p_to); dia.newline(); int field_cc = dia.getnb(); dia.newf_str (MSG_U(F_CC,"CC"),edit.cc,65); dia.set_helpdia (p_cc); dia.newline(); int field_folder = dia.getnb(); dia.newf_str (MSG_U(F_FCC,"Copy to folder"),newmsg.fcc,40); dia.set_helpdia (p_folder); dia.newline(); int field_bcc = dia.getnb(); dia.newf_str (MSG_U(F_BCC,"Blind carbon copy"),edit.bcc,65); dia.set_helpdia (p_bcc); dia.newline(); dia.newf_str (MSG_U(F_SUBJECT,"Subject"),newmsg.subject,65); dia.newline(); int field_attach = dia.getnb(); SSTRING attach_info; dia.newf_str (MSG_U(F_ATTACH,"Attach"),attach_info,65); dia.set_lastreadonly(); dia.set_helpdia (p_attach); dia.newline(); dia.gui_end(); dia.newline(); int butmask; dia.gui_form(); void *codata = glocal.c->codialog_setup (dia,butmask); dia.gui_end(); dia.newline(); int nof = 0; if (glocal.priv->cmd == COMPOSE_REPLY) nof = dia.getnb(); int field_text = dia.getnb(); dia.newf_textarea (NULL,newmsg.text,80,20); dia.gui_dispolast (GUI_H_LEFT,2,GUI_V_CENTER,1); dia.setbutinfo (MENU_USR1,MSG_U(B_SEND,"Send"),MSG_R(B_SEND)); dia.setbutinfo (MENU_USR2,MSG_U(B_OUTBOX,"Outbox"),MSG_R(B_OUTBOX)); dia.setbutinfo (MENU_USR3,MSG_U(B_POSTPONE,"Postpone"),MSG_R(B_POSTPONE)); dia.setbutinfo (MENU_USR4,MSG_R(B_CLEAR),MSG_R(B_CLEAR)); dia.setbutinfo (MENU_USR5,MSG_U(B_INSERT,"Insert file"),MSG_R(B_INSERT)); while (1){ MENU_STATUS code = dia.edit (title.get() ,"",help_nil,nof ,MENUBUT_CANCEL |MENUBUT_USR1|MENUBUT_USR2|MENUBUT_USR3|MENUBUT_USR4|MENUBUT_USR5 |butmask); if (code == MENU_ESCAPE || code == MENU_CANCEL){ glocal.c->cancel (codata,newmsg); break; }else if (code == MENU_USR1 || code == MENU_USR2){ dia.save(); compose_saveedit (newmsg,edit); if (glocal.c->codialog_validate(codata,dia,nof)!=-1){ ATTACHEMENTS tbatt; if (mailsend_validattach (attachs,tbatt)){ glocal.c->archive(codata,newmsg,tbatt); if (code == MENU_USR1){ if (glocal.c->send(codata,newmsg,tbatt)!=-1){ if (msg != NULL) msg->set_replied(true); break; } }else if (code == MENU_USR2){ newmsg.date = time(NULL); if (glocal.c->outbox(codata,newmsg,tbatt)!=-1){ if (msg != NULL) msg->set_replied(true); break; } } } } }else if (code == MENU_USR3){ dia.save(); compose_saveedit (newmsg,edit); newmsg.date = time(NULL); ATTACHEMENTS tbatt; if (mailsend_validattach(attachs,tbatt)){ glocal.c->postpone(codata,newmsg,tbatt); break; } }else if (code == MENU_USR4){ newmsg.text.setempty(); glocal.c->initnewmsg (newmsg.text); dia.reload (field_text); }else if (code == MENU_USR5){ dia.save(); compose_insert (newmsg.text); dia.reload (field_text); }else if (code == MENU_DUMP){ dia.save(); compose_saveedit (newmsg,edit); ATTACHEMENTS tbatt; if (mailsend_validattach (attachs,tbatt)){ glocal.c->postpone(codata,newmsg,tbatt); break; } }else if (code == MENU_MESSAGE){ dia.save(); if (must_end (info.msgs)){ dia.request_dump(); // We end whenever we get MENU_DUMP }else if (dialog_testmessage(p_to)){ compose_appendaddrs (glocal.c,dia,edit.to,field_to); }else if (dialog_testmessage(p_cc)){ compose_appendaddrs (glocal.c,dia,edit.cc,field_cc); }else if (dialog_testmessage(p_bcc)){ compose_appendaddrs (glocal.c,dia,edit.bcc,field_bcc); }else if (dialog_testmessage(p_folder)){ SSTRINGS folders; glocal.c->folderlist (newmsg.fcc); dia.reload (field_folder); }else if (dialog_testmessage(p_attach)){ glocal.c->editattach (attachs); attach_info.setempty(); int nb = attachs.getnb(); ATTACHEMENT *a = attachs.getitem(0); if (nb == 1){ attach_info.setfrom (a->getfname()); }else if (nb > 1){ attach_info.setfromf (MSG_U(I_INFOATTACH,"%d parts, %s, ...") ,nb,a->getfname()); } dia.reload (field_attach); }else{ glocal.c->codialog_buttons (codata,dia,code); } }else if (code > MENU_USR3){ dia.save(); compose_saveedit (newmsg,edit); glocal.c->codialog_buttons (codata,dia,code); } } if (msg != NULL){ msg->decrusage(); folders_free(); } glocal.c->codialog_end (codata); end = true; frame.newdocument(); frame.loop(); priv->framework_active = false; } static void f_framework (void *p) { MAIL_COMPOSE *c = (MAIL_COMPOSE*)p; c->start_framework(); } /* Manage the interactive framework */ PRIVATE void MAIL_COMPOSE::manage () { if (!priv->framework_active){ uithread (f_framework,this); }else{ dialog_sendmessage (priv->wakeup); } } /* Compose a new mail message */ PUBLIC void MAIL_COMPOSE::compose (EMAILADDRS &recipients) { priv->to = recipients; priv->msg = NULL; priv->cmd = COMPOSE_NEW; manage(); } PUBLIC void MAIL_COMPOSE::compose () { priv->to.remove_all(); priv->cc.remove_all(); priv->bcc.remove_all(); priv->msg = NULL; priv->cmd = COMPOSE_NEW; manage(); } /* Reply to a mail message */ PUBLIC void MAIL_COMPOSE::reply (MAIL_MESSAGE &msg) { const char *name = msg.get_from(); const char *email = msg.getemail_from(); if (msg.get_reply()[0] != '\0'){ name = msg.get_reply(); email = msg.getemail_reply(); } priv->to.remove_all(); priv->to.set (name,email); priv->cc.remove_all(); priv->bcc.remove_all(); priv->msg = &msg; priv->cmd = COMPOSE_REPLY; manage(); } PUBLIC void MAIL_COMPOSE::reply ( MAIL_MESSAGE &msg, EMAILADDRS &to, EMAILADDRS &cc, EMAILADDRS &bcc) { priv->msg = &msg; priv->to = to; priv->cc = cc; priv->bcc = bcc; priv->cmd = COMPOSE_REPLY; manage(); } /* Forward a mail message */ PUBLIC void MAIL_COMPOSE::forward (MAIL_MESSAGE &msg) { priv->msg = &msg; priv->cmd = COMPOSE_FORWARD; manage(); } /* Continue composition of a mail message */ PUBLIC void MAIL_COMPOSE::resume (MAIL_MESSAGE &msg) { priv->msg = &msg; priv->cmd = COMPOSE_RESUME; manage(); }