//
//  TPHONE.C
//  Pegasus Mail for Windows form, providing a telephone message
//  interface.
//
//  Copyright (c) 1994-95, David Harris, All Rights Reserved.
//
//  The author grants explicit permission for this source code to be
//  used or modified as required, subject only to the conditions that
//  the copyright notices above are preserved and that by using this
//  code you agree that the code is provided without warranty of any
//  kind, either explicit or implied, and you use it at your own
//  risk.
//

#define STRICT
#include <windows.h>
#include <bwcc.h>
#include <stdio.h>
#include <string.h>
#include "..\wpmforms.h"
#include "tphone.h"         //  Dialog control item IDs
#include <ctype.h>          //  For toupper()
#include <io.h>             //  For filelength() and fileno()
#include <alloc.h>          //  For malloc() and free()  

//  Form dialogs and callbacks: a form DLL can export a function
//  which WinPMail's form manager will call with Windows messages
//  destined for the form's dialog or window (such as menu selections
//  and so forth). The function takes the following form:

typedef long pascal far (*FORM_CALLBACK) (HWND hWnd, WORD wMsg,
   WPARAM wParam, LPARAM lParam);

//  The return from a form callback is passed back through the
//  Windows call chain if non-zero, otherwise the default window
//  proc is called. The reasons we call this function instead of
//  simply sending messages to the dialog itself are:
//
//   1: Dialogs can only return Boolean values, whereas the callback
//      can provide the long value Windows expects to pass back
//      through the calling chain.
//
//   2: Having a separate callback means that it is potentially
//      possible to have a form which does not create a dialog.
//
//
//  Minimum interface: the minimum interface a form DLL must provide
//  is a routine called "forminit" which is exported by name. "forminit"
//  has the following prototype:
//
//  WORD FAR PASCAL _export FORMINIT (WORD version, int variant, HWND hParent,
//      char *data, HWND *hDialog, char *callback_name);
//
//  "version" is passed in with the version of the WinPMail forms
//     manager which is running.
//  "variant" indicates what type of form is required - the following
//     values are currently defined:
//       0: Create a form for composing a message
//       1: Create a form for reading a message
//  "hParent" contains the handle of the WinPMail MDI child window
//     which is to contain the form.
//  "data" contains any string defined as being required for the
//     form in the menu interface.
//  "hDialog" should be filled in with the window handle of the
//     modeless dialog created within the MDI child window.
//  "callback_name" (optional) should be filled in with the name of the
//     function in the DLL of the exported function to which messages
//     should be sent or NULL if there is none. If NULL, messages are
//     sent to the dialog returned in "hDialog". You will use an
//     indirect callback of this kind when your extension does not
//     create a dialog within the enclosing parent window.
//
//  When forminit is called, the DLL should register any window
//  classes it needs then create the dialog within the MDI parent
//  window and size it to the correct size. On return WinPMail will
//  resize the parent window to enclose the dialog correctly. The
//  DLL should NOT make the dialog visible - WinPMail will do that
//  as required.

#define WM_MARGIN (WM_USER + 1099)
#define WM_SETDIR (WM_USER + 400)
#define WM_ADDFILE (WM_USER + 401)
#define WM_STARTUP (WM_USER + 403)
#define WM_GET_ALIST (WM_USER + 404)

#define IDC_QUICKHELP_TO   970
#define IDC_QUICKHELP_CC   971


int register_form_classes (void);


HINSTANCE  hLibInstance;            // set in LibMain, used throughout the DLL
char szFormDlgName [] = "TM";    // Name of dialog resource template.
char szFormDlgClassName [] =
   "bordlg_tm";                  // Class name for the form dialog.

char copyself;                   // If NZ, keep a copy to self

char *months [] =
   {
   "Jan", "Feb", "Mar",
   "Apr", "May", "Jun",
   "Jul", "Aug", "Sep", 
   "Oct", "Nov", "Dec"
   };

#pragma warn -par


WORD FAR PASCAL _export FORMINIT (WORD version, int variant, HWND hParent,
   char *data, HWND *hDialog, char *callback_name)
   {
   //  First, check to see if the version of the form manager is
   //  one we can work with.

   RECT r;
   char szBuf [80];
   int i;
   HWND hControl;
   BYTE tm [7];

   if ((version & 0xFF00) > 0x100) return 0;

   //  Now check the variant number; for a telephone form, we only
   //  provide a composition format.

   if (variant != 0) return 0;

   (*hDialog) = CreateDialog (hLibInstance, (LPCSTR) szFormDlgName, hParent, NULL);
   if ((*hDialog) == NULL) return 0;
   GetClientRect (*hDialog, &r);
   MoveWindow (*hDialog, 0, 0, r.right, r.bottom, FALSE);
   hControl = GetDlgItem (*hDialog, IDC_F_PHONETYPE);
   for (i = 1; i < 5; i ++)
      {
      LoadString (hLibInstance, i, szBuf, sizeof (szBuf));
      SendMessage (hControl, CB_ADDSTRING, 0, (LPARAM) szBuf);
      }
   SendMessage (hControl, CB_SETCURSEL, 0, 0);
   CheckDlgButton (*hDialog, IDC_F_PHONED, 1);
   CheckDlgButton (*hDialog, IDC_F_PLEASECALL, 1);

   SendMessage (hParent, WM_F_GETDATETIME, 0, (LPARAM) tm);
   sprintf (szBuf, "%d %s %d, %02d:%02d", tm [2], months [tm [1] - 1],
      tm [0], tm [3], tm [4]);
   SetDlgItemText (*hDialog, IDC_F_DATETIME, szBuf);

   //  Some default values can be passed in the "data" parameter
   if ((data != NULL) && (*data))
     {
     if (toupper (*data) == 'Y') 
        CheckDlgButton (*hDialog, IDC_F_URGENT, 1);
     if (*(data + 1) && *(data + 2))
        if (toupper (*(data + 2)) == 'Y')
           copyself = 1;
     if (*(data + 3) && *(data + 4))
        SetDlgItemText (*hDialog, IDC_F_AREACODE, data + 4);
     }

   SetFocus (GetDlgItem (*hDialog, IDC_F_TO));
   return 1;
   }


static void strip_ampersands (char *source)
   {
   //  Strip out any ampersands (&) which might appear in a 
   //  string (typically the title of a control). The string
   //  is converted in place.

   char *dest;

   for (dest = source; *source; source ++)
      if (*source != '&') *dest ++ = *source;
   *dest = '\0';
   }


int send_the_message (HWND hWnd)
   {
   //  Called when the user clicks the "send" button. This routine
   //  gets a temporary filename from WinPMail, writes the message
   //  text into it then asks WinPMail to send it.
   //  Returns: 1 if the message is sent OK
   //           0 if the delivery failed

   char szBuf [256], fname [80], subject [80], *gender, *s, *s2;
   HWND hParent;
   FILE *fil;
   int result, id, c;
   char *message_data;
   unsigned int datalength;

   hParent = GetParent (hWnd);
   SendMessage (hParent, WM_F_NEWMESSAGE, 0, 0);
   SendMessage (hParent, WM_F_TEMPFILE, sizeof (fname), (LPARAM) fname);
   if ((fil = fopen (fname, "w+t")) == NULL)
      return 0;

   GetDlgItemText (hWnd, IDC_F_TO, szBuf, sizeof (szBuf));
   SendMessage (hParent, WM_F_TO, 0, (LPARAM) szBuf);

   GetDlgItemText (hWnd, IDC_F_CC, szBuf, sizeof (szBuf));
   if (szBuf [0]) SendMessage (hParent, WM_F_CC, 0, (LPARAM) szBuf);

   if (IsDlgButtonChecked (hWnd, IDC_F_URGENT))
      SendMessage (hParent, WM_F_URGENT, 1, 0);

   if (copyself) SendMessage (hParent, WM_F_COPYSELF, 1, 0);

   GetDlgItemText (hWnd, IDC_F_NAME, szBuf, sizeof (szBuf));
   wsprintf (subject, "Phone call: %.45s", szBuf);

   //  Now, we take a sort of semi-intelligent stab at working out
   //  the gender of the caller...

   gender = "He/She";
   if (strnicmp (szBuf, "Mr ", 3) == 0) gender = "He";
   if ((strnicmp (szBuf, "Mrs", 3) == 0) ||
      (strnicmp (szBuf, "Ms", 2) == 0) ||
      (strnicmp (szBuf, "Miss", 4) == 0))
      gender = "She";

   SendMessage (hParent, WM_F_SUBJECT, 0, (LPARAM) subject);

   GetDlgItemText (hWnd, IDC_F_DATETIME, subject, sizeof (subject));
   fprintf (fil, "**   At %s,\n", subject);
   GetDlgItemText (hWnd, IDC_F_OF, subject, sizeof (subject));
   fprintf (fil, "**   %s, of %s", szBuf, subject);

   id = IDC_F_PHONED;
   if (IsDlgButtonChecked (hWnd, IDC_F_CALLED)) id = IDC_F_CALLED;
   if (IsDlgButtonChecked (hWnd, IDC_F_CALLEDBACK)) id = IDC_F_CALLEDBACK;
   GetDlgItemText (hWnd, id, szBuf, sizeof (szBuf));
   strip_ampersands (szBuf);
   fprintf (fil, " %s.\n", szBuf);
   fprintf (fil, "**   Phone number: ", szBuf, subject);
   GetDlgItemText (hWnd, IDC_F_AREACODE, subject, sizeof (subject));
   if (subject [0]) fprintf (fil, "(%s) ", subject);
   GetDlgItemText (hWnd, IDC_F_PHONE, subject, sizeof (subject));
   if (subject [0]) fprintf (fil, "%s", subject);
   GetDlgItemText (hWnd, IDC_F_EXTN, subject, sizeof (subject));
   if (subject [0]) fprintf (fil, " (Extn %s)", subject);
   fprintf (fil, "\n");

   id = IDC_F_PLEASECALL;
   if (IsDlgButtonChecked (hWnd, IDC_F_WILLCALL)) id = IDC_F_WILLCALL;
   if (IsDlgButtonChecked (hWnd, IDC_F_NOACTION)) id = IDC_F_NOACTION;
   fprintf (fil, "**   ");
   switch (id)
      {
      case IDC_F_PLEASECALL :
         fprintf (fil, "%s would like you to call back", gender);
         break;

      case IDC_F_WILLCALL :
         fprintf (fil, "%s will call again later", gender);
         break;

      default :
         fprintf (fil, "No further action is required on your part");
         break;
      }
   fprintf (fil, ".\n");

   s = (char *) SendMessage (hParent, WM_F_GETTEXT, IDC_F_MESSAGE, 0);
   if (s != NULL)
      {
      fprintf (fil, "\n%s also left the following message:\n\n", gender);
      for (s2 = s; *s2; s2 ++) fputc (*s2, fil);
      SendMessage (hParent, WM_F_FREE, 0, (LPARAM) s);
      }

   //  Now we load what we've written to disk into a memory
   //  image ready for sending. This is necessary to work around
   //  two problems in WinPMail 2.01 which are fixed in later
   //  versions.

   fflush (fil);
   rewind (fil);
   datalength = filelength (fileno (fil));
   if ((message_data = (char *) malloc (datalength + 16)) == NULL)
      result = 0;
   else
      {
      s = message_data;
      while ((c = fgetc (fil)) != EOF)
         *s ++ = c;
      *s = '\0';

      SendMessage (hParent, WM_F_MESSAGETEXT, 0, (LPARAM) message_data);
      result = (int) SendMessage (hParent, WM_F_SENDMESSAGE, 0, 0);
      free (message_data);
      }

   fclose (fil);
   remove (fname);
   return result;
   }


LONG FAR PASCAL _export FormProc (HWND hWnd, WORD wMsg, 
   WORD wParam, LONG lParam)
   {
   //  Service routine for the form's enclosed dialog. This is a
   //  standard windows WndProc.

   DWORD dwResult = 0;
   BOOL fCallDefProc = TRUE;

   switch (wMsg)
      {
      case WM_FM_INITFOCUS :
         SetFocus (GetDlgItem (hWnd, IDC_F_TO));
         break;

      case WM_COMMAND :
         fCallDefProc = FALSE;
         switch (wParam)
            {
            case IDC_F_CANCEL :
               PostMessage (GetParent (hWnd), WM_CLOSE, 0, 0);
               break;

            case IDC_F_RECADDR :
               SendMessage (GetParent (hWnd), WM_F_QUICKADDRESS, 
                  (WPARAM) (GetDlgItem (hWnd, IDC_F_TO)), 0);
               break;

            case IDC_F_RECADDR2 :
               SendMessage (GetParent (hWnd), WM_F_QUICKADDRESS, 
                  (WPARAM) (GetDlgItem (hWnd, IDC_F_CC)), 0);
               break;

            case IDC_F_SEND :
               if (send_the_message (hWnd))
                  PostMessage (GetParent (hWnd), WM_CLOSE, 0, 0);
               break;
            }
         break;
      }

   if (fCallDefProc)
      dwResult = BWCCDefDlgProc (hWnd, wMsg, wParam, lParam);

   return dwResult;
   }


#pragma warn -sus

void unregister_form_classes (void)
   {
   //  Remove any classes associated with the form; we have the
   //  same problem here as we do with registering the classes
   //  for the DLL - we only want to deregister the classes on
   //  the last time we're unloaded.

   if (GetModuleUsage (hLibInstance) > 1) return;      //  Not a problem
   UnregisterClass (szFormDlgClassName, hLibInstance);
   }


BOOL FAR PASCAL LibMain (HINSTANCE hInst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
   {
   WNDCLASS wc;

   if (! hLibInstance)
      {
      hLibInstance = hInst;
      BWCCGetVersion ();      //  Forces BWCC to be dynamically loaded.

      //  Register any window classes used by the form. Forms will usually
      //  register either one or occasionally two classes which define
      //  the composition and reader dialogs created by the DLL.
      //
      //  There's a gotcha here, of course (aren't there always, in
      //  Windows?)... You can't register a window class more than once,
      //  so if the DLL has already been loaded and the user asks to
      //  create a second instance of the form, we have to be careful
      //  not to re-register the class. We do this by checking the
      //  instance usage counter of the DLL - if it's greater than 1,
      //  then we DON'T register the classes.

      wc.style          = WS_CHILD;
      wc.lpfnWndProc    = FormProc;
      wc.cbClsExtra     = 0;
      wc.cbWndExtra     = DLGWINDOWEXTRA;
	   wc.hInstance      = hLibInstance;
	   wc.hIcon          = NULL;
      wc.hCursor        = LoadCursor (NULL, IDC_ARROW);
      wc.hbrBackground  = (HBRUSH) (COLOR_WINDOW + 1);
      wc.lpszMenuName   = NULL;
      wc.lpszClassName  = szFormDlgClassName;
      if (! RegisterClass (&wc))
         MessageBeep (0);
      }

   return (TRUE);             // Initialization went OK
   }

