home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / util / comm / news102.sit / NewsWatcher / source / netstuff.c < prev    next >
Text File  |  1991-04-03  |  14KB  |  623 lines

  1. /*----------------------------------------------------------
  2. #
  3. #    NewsWatcher    - Macintosh NNTP Client Application
  4. #
  5. #    Written by Steven Falkenburg
  6. #    ⌐1990 Apple Computer, Inc.
  7. #
  8. #-----------------------------------------------------------
  9. #
  10. #    netstuff.c
  11. #
  12. #    The netstuff code module contains several routines which
  13. #    handle network specific tasks of the program.  Among
  14. #    these are user authentication, and high-level file xfer
  15. #    calls.
  16. #
  17. #-----------------------------------------------------------*/
  18.  
  19. #pragma segment netstuff
  20.  
  21. #include "compat.h"
  22. #include <String.h>
  23. #include <StdIO.h>
  24.  
  25. #ifdef PROTOS
  26. #include <Types.h>
  27. #include <TextEdit.h>
  28. #include <Dialogs.h>
  29. #include <Files.h>
  30. #include <Memory.h>
  31. #include <Errors.h>
  32. #include <Events.h>
  33. #include <Fonts.h>
  34. #include <Packages.h>
  35. #include <Lists.h>
  36. #include <ToolUtils.h>
  37. #include <Strings.h>
  38. #endif
  39.  
  40. #include "MacTCPCommonTypes.h"
  41. #include "AddressXLation.h"
  42. #include "TCPPB.h"
  43. #include "nntp.h"
  44. #include "netstuff.h"
  45. #include "miscstuff.h"
  46. #include "userint.h"
  47. #include "newsprocess.h"
  48. #include "TCPHi.h"
  49. #include "FTPLow.h"
  50. #include "NNTPLow.h"
  51. #include "SMTPLow.h"
  52.  
  53. static char gPwStr[256];        /* the user's password */
  54. unsigned long gSMTPAddress;        /* the ip address of the SMTP host */
  55.  
  56. /* local protos */
  57.  
  58. pascal Boolean PasswordFilter(DialogPtr theDialog,EventRecord *theEvent,short *itemHit);
  59. pascal void DNRResultProc(struct hostInfo *hInfoPtr,char *userDataPtr);
  60.  
  61.  
  62. /*    ChangeServerAddress is called to get a new name/address for the news
  63.     or main server.  The new address will be stored in the prefs file.
  64. */
  65.  
  66. void ChangeServerAddress(Boolean forNews)
  67. {
  68.     DialogPtr theDlg;
  69.     short iType;
  70.     Handle iHndl;
  71.     Rect iBox;
  72.     Str255 serverName;
  73.     short item;
  74.     extern Boolean gDone;
  75.     extern TPrefRec gPrefs;
  76.     
  77.     if (forNews) {
  78.         if (gPrefs.newsServerName[0] == '\0') {
  79.             SysBeep(1);
  80.             BlockMove(kNNTPName,serverName,kNNTPNameLen);
  81.         }
  82.         else
  83.             BlockMove(gPrefs.newsServerName,serverName,(gPrefs.newsServerName)[0]+1);
  84.         theDlg = GetNewDialog(kNewsServerAddrID,nil,(WindowPtr)-1);
  85.     }
  86.     else {
  87.         if (gPrefs.mailServerName[0] == '\0') {
  88.             SysBeep(1);
  89.             BlockMove(kSMTPName,serverName,kSMTPNameLen);
  90.         }
  91.         else
  92.             BlockMove(gPrefs.mailServerName,serverName,(gPrefs.mailServerName)[0]+1);
  93.         theDlg = GetNewDialog(kMailServerAddrID,nil,(WindowPtr)-1);
  94.     }
  95.     
  96.     OutlineOK(theDlg);
  97.     GetDItem(theDlg,3,&iType,&iHndl,&iBox);
  98.     SetIText(iHndl,serverName);
  99.     SelIText(theDlg,3,0L,32767L);
  100.     do {
  101.         ModalDialog(CmdKeyFilter,&item);
  102.     } while (item!=okButton && item!=cancelButton);
  103.     GetIText(iHndl,serverName);
  104.     DisposDialog(theDlg);
  105.     
  106.     if (forNews) {
  107.         if (item==okButton)
  108.             BlockMove(serverName,gPrefs.newsServerName,serverName[0]+1);
  109.     }
  110.     else {
  111.         if (item==okButton)
  112.             BlockMove(serverName,gPrefs.mailServerName,serverName[0]+1);
  113.     }
  114.     
  115.     if (!gDone && item==okButton) {
  116.         ParamText("\pYou must quit and restart the program for this change to take effect.","\p","\p","\p");
  117.         NoteAlert(kErrDlg,nil);
  118.     }
  119. }
  120.  
  121.  
  122. /*    GetConfiguration is called to get the news/mail server ip addresses,
  123.     given their names from the preferences file.
  124. */
  125.  
  126. void GetConfiguration(void)
  127. {
  128.     extern unsigned long gNNTPAddress;
  129.     extern TPrefRec gPrefs;
  130.     Str255 name;
  131.     
  132.     if (gPrefs.newsServerName[0] == '\0' || gPrefs.mailServerName[0] == '\0') {
  133.         ChangeServerAddress(true);
  134.         if (gPrefs.newsServerName[0] == '\0') {
  135.             gNNTPAddress = kNNTPAddress;
  136.             return;
  137.         }
  138.         ChangeServerAddress(false);
  139.         if (gPrefs.mailServerName[0] == '\0') {
  140.             gSMTPAddress = kSMTPAddress;
  141.             return;
  142.         }
  143.     }
  144.     BlockMove(gPrefs.newsServerName,name,(gPrefs.newsServerName)[0]+1);
  145.     p2cstr((char *)name);
  146.     if (ConvertStringToAddr((char *)name,&gNNTPAddress)!=noErr)
  147.         gNNTPAddress = kNNTPAddress;
  148.     BlockMove(gPrefs.mailServerName,name,(gPrefs.mailServerName)[0]+1);
  149.     p2cstr((char *)name);
  150.     if (ConvertStringToAddr((char *)name,&gSMTPAddress)!=noErr)
  151.         gSMTPAddress = kSMTPAddress;
  152. }
  153.  
  154.  
  155. /*    This is the completion routine used for name-resolver calls.
  156.     It sets the userDataPtr flag to indicate the call has completed.
  157. */
  158.  
  159. pascal void DNRResultProc(struct hostInfo *hInfoPtr,char *userDataPtr)
  160. {
  161. #pragma unused (hInfoPtr)
  162.  
  163.     *userDataPtr = 0xff;
  164. }
  165.  
  166.  
  167. /*    ConvertStringToAddr is a simple call to get a host's IP number, given the name
  168.     of the host.
  169. */
  170.  
  171. OSErr ConvertStringToAddr(char *name,unsigned long *netNum)
  172. {
  173.     struct hostInfo hInfo;
  174.     OSErr result;
  175.     char done = 0x00;
  176.     extern Boolean gCancel;
  177.  
  178.     if ((result = OpenResolver(nil)) == noErr) {
  179.         result = StrToAddr(name,&hInfo,DNRResultProc,&done);
  180.         if (result == cacheFault)
  181.             while (!done)
  182.                 ; /* wait for cache fault resolver to be called by interrupt */
  183.         CloseResolver();
  184.         if ((hInfo.rtnCode == noErr) || (hInfo.rtnCode == cacheFault)) {
  185.             *netNum = hInfo.addr[0];
  186.             strcpy(name,hInfo.cname);
  187.             name[strlen(name)-1] = '\0';
  188.             return noErr;
  189.         }
  190.     }
  191.     *netNum = 0;
  192.  
  193.     return result;
  194. }
  195.  
  196.  
  197. /*    PasswordFilter is the dialog filter used to switch all keys pressed
  198.     into bullets (Ñ) to hide the user's password from view.
  199. */
  200.  
  201. pascal Boolean PasswordFilter(DialogPtr theDialog,EventRecord *theEvent,short *itemHit)
  202. {
  203.     DialogPeek dPeek;
  204.     char theChar;
  205.     short selStart,selEnd;
  206.     
  207.     dPeek = (DialogPeek) theDialog;
  208.     
  209.     if ((theEvent->what == keyDown) || (theEvent->what == autoKey)) {
  210.         if ((theEvent->modifiers & cmdKey) != 0) {
  211.             return CmdKeyFilter(theDialog,theEvent,itemHit);
  212.         }
  213.         if (dPeek->editField == 2) {
  214.             theChar = theEvent->message & charCodeMask;
  215.             selStart = (**(dPeek->textH)).selStart;
  216.             selEnd = (**(dPeek->textH)).selEnd;
  217.             switch (theChar) {
  218.                 case 0x08:        /* backspace */
  219.                     if (selStart == selEnd) {
  220.                         if (selStart > 0)
  221.                             BlockMove((Ptr)gPwStr + selStart,(Ptr)gPwStr + selStart-1,strlen(gPwStr)-selStart+1);
  222.                     }
  223.                     else
  224.                         BlockMove((Ptr)gPwStr + selEnd,(Ptr)gPwStr + selStart,strlen(gPwStr)-selEnd+1);
  225.                     break;
  226.                 case CR:    /* CR     */
  227.                 case 0x03:    /* enter */
  228.                     *itemHit = okButton;
  229.                     return true;
  230.                     break;
  231.                 case 0x09:    /* tab     */
  232.                 case 0x1c:    /* left */
  233.                 case 0x1d:    /* right */
  234.                 case 0x1e:    /* up     */
  235.                 case 0x1f:    /* down */
  236.                     return false;
  237.                     break;
  238.                 default:
  239.                     BlockMove((Ptr)gPwStr+selEnd,(Ptr)gPwStr+selEnd+1,strlen(gPwStr)-selEnd+1);
  240.                     *(gPwStr+selStart) = theChar;
  241.                     theEvent->message = 0xffffff00 + 'Ñ';
  242.                     return false;
  243.                     break;
  244.             }
  245.         }
  246.         if ((theChar == CR) || (theChar == 0x03))    {
  247.             *itemHit = okButton;
  248.             return true;
  249.         }
  250.     }
  251.         
  252.     return false;
  253. }
  254.  
  255.  
  256. /*    GetUInfo displays modal dialogs for the user to enter their
  257.     login id, host, and password for authentication.
  258. */
  259.  
  260. Boolean GetUInfo(Str255 login,Str255 pass,Str255 host)
  261. {
  262.     DialogPtr theDlg;
  263.     short item,iType;
  264.     Handle iHndl;
  265.     Rect iRect;
  266.         
  267.     theDlg = GetNewDialog(kLoginDlg,nil,(WindowPtr)-1);
  268.     OutlineOK(theDlg);
  269.     GetDItem(theDlg,3,&iType,&iHndl,&iRect);
  270.     SetIText(iHndl,(StringPtr)c2pstr((char *)host));
  271.     GetDItem(theDlg,4,&iType,&iHndl,&iRect);
  272.     SetIText(iHndl,(StringPtr)c2pstr((char *)login));
  273.     do
  274.         ModalDialog(CmdKeyFilter,&item);
  275.     while (item != okButton && item != cancelButton);
  276.     
  277.     GetDItem(theDlg,3,&iType,&iHndl,&iRect);
  278.     GetIText(iHndl,host);
  279.     GetDItem(theDlg,4,&iType,&iHndl,&iRect);
  280.     GetIText(iHndl,login);
  281.     
  282.     DisposDialog(theDlg);
  283.  
  284.     ParamText(host,"\p","\p","\p");
  285.  
  286.     p2cstr((char *)login);
  287.     p2cstr((char *)host);
  288.  
  289.     if (item == cancelButton)
  290.         return false;
  291.     
  292.     if (!host[0] || !login[0])
  293.         return false;
  294.     
  295.     theDlg = GetNewDialog(kPassDlg,nil,(WindowPtr)-1);
  296.     OutlineOK(theDlg);
  297.  
  298.     *gPwStr = '\0';
  299.  
  300.     do
  301.         ModalDialog(PasswordFilter,&item);
  302.     while (item != okButton && item != cancelButton);
  303.  
  304.     DisposDialog(theDlg);    
  305.     if (item == cancelButton)
  306.         return false;
  307.  
  308.     strcpy(pass,gPwStr);
  309.  
  310.     return true;
  311. }
  312.  
  313.  
  314. /*    Authenticate is called to check the accuracy of a user's id and
  315.     password.  Eventually, this procedure could be replaced with a
  316.     more secure method.  Currently, FTP is used for authentication.
  317. */
  318.  
  319. Boolean Authenticate(void)
  320. {
  321.     extern Boolean gAuthenticated;
  322.     extern char gPass[];
  323.     extern TPrefRec gPrefs;
  324.     unsigned long connID;
  325.     
  326.     if (gAuthenticated)
  327.         return true;
  328.     
  329.     if (!GetUInfo((StringPtr)gPrefs.name,(StringPtr)gPass,(StringPtr)gPrefs.host))
  330.         return false;
  331.         
  332.     StatusWindow("Authenticating user...",-1);
  333.     
  334.     if (FTPConnect(&connID,(char *)gPrefs.host,(char *)gPrefs.name,gPass)!=noErr) {
  335.         FTPDisconnect(connID);
  336.         CloseStatusWindow();
  337.         ParamText("\pIncorrect user information.","\p","\p","\p");
  338.         NoteAlert(kErrDlg,nil);
  339.         return false;
  340.     }
  341.     FTPDisconnect(connID);
  342.     CloseStatusWindow();
  343.  
  344.     gAuthenticated = true;
  345.     return true;
  346. }
  347.  
  348.  
  349. /*    Logout removes the user's password from memory.
  350. */
  351.  
  352. void Logout(void)
  353. {
  354.     extern Boolean gAuthenticated;
  355.     extern char gPass[];
  356.  
  357.     strcpy(gPass,"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
  358.     gAuthenticated = false;
  359. }
  360.  
  361.  
  362. /*    GetFromNet gets a newsrc file from the user's remote account.
  363. */
  364.  
  365. void GetFromNet(void)
  366. {
  367.     extern char gPass[];
  368.     extern TPrefRec gPrefs;
  369.     
  370.     unsigned long connID;
  371.     Ptr newsData;
  372.     char *current;
  373.     TwindowInfo *info;
  374.     WindowPtr window;
  375.     OSErr err;
  376.     extern TPrefRec gPrefs;
  377.     
  378.     if (!Authenticate())
  379.         return;
  380.     
  381.     StatusWindow("Establishing FTP Connection...",-1);
  382.     
  383.     if (FTPConnect(&connID,(char *)gPrefs.host,(char *)gPrefs.name,gPass)!=noErr) {
  384.         FTPDisconnect(connID);
  385.         CloseStatusWindow();
  386.         ParamText("\pFile not retrieved successfully.","\p","\p","\p");
  387.         NoteAlert(kErrDlg,nil);
  388.         return;
  389.     }
  390.     
  391.     if ((err = FTPViewFile(connID,&newsData,".newsrc"))!=noErr) {
  392.         FTPDisconnect(connID);
  393.         CloseStatusWindow();
  394.         SetCursor(&QDARROW);
  395.         ParamText("\pFile not retrieved successfully.","\p","\p","\p");
  396.         NoteAlert(kErrDlg,nil);
  397.         return;
  398.     }
  399.     CloseStatusWindow();
  400.  
  401.     FTPDisconnect(connID);
  402.     
  403.     NewGroupWindow("\pnewsrc");
  404.     info = (TwindowInfo *)GetWRefCon(window = FrontWindow());
  405.     
  406.     BlockMove("\pnewsrc",info->diskFile,8);
  407.     info->diskVRefNum = 0;
  408.     LDoDraw(false,(ListHandle)info->data);
  409.     current = newsData;
  410.     while (*current)
  411.         ProcessLine(¤t,window);
  412.     LDoDraw(true,(ListHandle)info->data);
  413.     info->changed = false;
  414.     info->saved = false;
  415.     
  416.     if (gPrefs.openWindowsZoomed)
  417.         ToggleZoom(window);
  418.     ShowWindow(window);
  419.     SetPort(window);
  420.     InvalRect(&window->portRect);
  421.     MyDisposPtr(newsData);
  422. }
  423.  
  424.  
  425. /*    SendToNet sends a user group list to a user's remote account for storage
  426.     as a newsrc file.
  427. */
  428.  
  429. void SendToNet(void)
  430. {
  431.     extern char gPass[];
  432.     extern TPrefRec gPrefs;
  433.     char tmpStr[256];
  434.     char *newsData;
  435.     long newsDataLen;
  436.     long first;
  437.     short offset;
  438.     TWList *current;
  439.     TGroup *theGroup;
  440.     TReadRec *read;
  441.     TwindowInfo *info;
  442.     WindowPtr window;
  443.     unsigned long connID;
  444.     
  445.     window = FrontWindow();
  446.     if (!window || !IsAppWindow(window))
  447.         return;
  448.     info = (TwindowInfo *)GetWRefCon(window);
  449.     if (info->kind != cUserGroup)
  450.         return;
  451.         
  452.     if (!Authenticate())
  453.         return;
  454.     
  455.     StatusWindow("Converting to newsrc format...",-1);
  456.     GiveTime(0);
  457.     
  458.     newsData = (char *)MyNewPtr(kMaxGroupLen);
  459.     if (MyMemErr() != noErr)
  460.         return;
  461.         
  462.     newsDataLen = 0;
  463.     newsData[newsDataLen] = '\0';
  464.     
  465.     /* update read lists */
  466.     
  467.     for (current = info->childList; current != nil; current = current->next)
  468.         MarkReadMsgs((TwindowInfo *) GetWRefCon(current->childWindow));
  469.     
  470.     /* process groups */
  471.     
  472.     for (theGroup = (TGroup *)info->data2; theGroup!=nil; theGroup=theGroup->next) {
  473.         strcat(newsData,theGroup->name);
  474.         strcat(newsData,": ");
  475.         
  476.         first = 1;
  477.         for (read = theGroup->read; read!=nil; read = read->next) {
  478.             if ( (read->firstRead-1 - first) >= 0) {
  479.                 sprintf(tmpStr,"%lu-%lu",first,(read->firstRead-1));
  480.                 if (read->next)
  481.                     strcat(tmpStr,",");
  482.                 strcat(newsData,tmpStr);
  483.             }
  484.             first = 1 + read->lastRead;
  485.         }
  486.         
  487.         /* mark read to last message of group */
  488.     
  489.         if (theGroup->lastMess >= first) {
  490.                 sprintf(tmpStr,", %lu-%lu",first,theGroup->lastMess);
  491.                 if (first==1)
  492.                     offset=1;
  493.                 else
  494.                     offset=0;
  495.                 strcat(newsData,tmpStr+offset);
  496.         }
  497.         
  498.         strcat(newsData,CRSTR);
  499.     }
  500.  
  501.     StatusWindow("Establishing FTP Connection...",-1);
  502.     GiveTime(0);
  503.     
  504.     if (FTPConnect(&connID,(char *)gPrefs.host,(char *)gPrefs.name,gPass)!=noErr) {
  505.         FTPDisconnect(connID);
  506.         CloseStatusWindow();
  507.         ParamText("\pFile not sent successfully.","\p","\p","\p");
  508.         NoteAlert(kErrDlg,nil);
  509.         return;
  510.     }
  511.     
  512.     if (FTPPutFile(connID,".newsrc",newsData,strlen(newsData))!=noErr) {
  513.         CloseStatusWindow();
  514.         ParamText("\pFile not sent successfully.","\p","\p","\p");
  515.         NoteAlert(kErrDlg,nil);
  516.     }
  517.  
  518.     FTPDisconnect(connID);
  519.  
  520.     /* newsdata has already been disposed */
  521. }
  522.  
  523.  
  524. /*    DoSendMsg either posts a message or sends the message through
  525.     electronic mail (SMTP) after converting the appropriate header
  526.     fields, etc...
  527. */
  528.  
  529. Boolean DoSendMsg(TwindowInfo *info)
  530. {
  531.     Handle sendText;
  532.     unsigned short length;
  533.     Boolean result = false;
  534.     long offset;
  535.     char mungeText1[256];
  536.     char mungeText2[256];
  537.     char mungeText3[256];
  538.     
  539.     strcpy(mungeText1,CRSTR);
  540.     strcat(mungeText1,CRSTR);
  541.  
  542.     strcpy(mungeText2,CRSTR);
  543.     strcat(mungeText2,"From");
  544.  
  545.     strcpy(mungeText3,CRSTR);
  546.     strcat(mungeText3,">From");
  547.     
  548.     if (!CheckHeader(info)) {
  549.         ParamText("\pInvalid sender name!  Can't send message.","\p","\p","\p");
  550.         StopAlert(kErrDlg,nil);
  551.         return false;
  552.     }
  553.     
  554.     StatusWindow("Sending Message...",-1);
  555.     GiveTime(0);
  556.     
  557.     sendText = (Handle) TEGetText((TEHandle)info->data);
  558.     length = (**((TEHandle)info->data)).teLength;
  559.     if (MyHandToHand(&sendText) != noErr)
  560.         return false;
  561.     MySetHandleSize(sendText,(long)length);
  562.     if (MyMemErr() != noErr)
  563.         return false;
  564.     
  565.     /* remove all "From"s at start of lines */
  566.     
  567.     for (offset = Munger(sendText,0L,mungeText1,2L,nil,0L);
  568.         offset>=0;
  569.         offset = Munger(sendText,offset,mungeText2,5L,mungeText3,6L))
  570.         length++;
  571.     
  572.     length--;
  573.     
  574.     /* convert all "." to "," at start of lines */
  575.     
  576.     if (**sendText=='.')
  577.         **sendText = ',';
  578.     
  579.     strcpy(mungeText1,CRSTR);
  580.     strcat(mungeText1,".");
  581.     strcat(mungeText1,CRSTR);
  582.     strcpy(mungeText2,CRSTR);
  583.     strcat(mungeText2,",");
  584.     strcat(mungeText2,CRSTR);
  585.     
  586.     for (offset = 0; offset>=0; offset = Munger(sendText,offset,mungeText1,3L,mungeText2,3L))
  587.         ;
  588.         
  589.     /* convert CR to CRLF */
  590.     
  591.     for (offset = 0; offset>=0; offset = Munger(sendText,offset,CRSTR,1L,CRLF,2L))
  592.         length++;
  593.     
  594.     length--;
  595.  
  596.     HLock(sendText);
  597.     
  598.     /* send message */
  599.     
  600.     switch (info->kind) {
  601.         case cSendMessage:
  602.             result = SendSMTP((char *)*sendText,length);
  603.             break;
  604.         case cPostMessage:
  605.             result = SendNNTP((char *)*sendText,length);
  606.             break;
  607.     }
  608.     MyDisposHandle(sendText);
  609.     
  610.     CloseStatusWindow();
  611.  
  612.     if (result == false) {
  613.         ParamText("\pMessage not sent successfully.","\p","\p","\p");
  614.         CautionAlert(kErrDlg,nil);
  615.     }
  616.     else
  617.         info->changed = false;
  618.     
  619.     return result;
  620. }
  621.  
  622.  
  623.