home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / URealNntp.cp < prev    next >
Encoding:
Text File  |  1994-04-13  |  10.9 KB  |  423 lines  |  [TEXT/MPS ]

  1. // Copyright © 1992 Peter Speck, speck@dat.ruc.dk. All rights reserved.
  2. // URealNntp.cp
  3.  
  4. #include "URealNntp.h"
  5. #include "UProgress.h"
  6. #include "UPrefsDatabase.h"
  7. #include "UPassword.h"
  8. #include "NetAsciiTools.h"
  9. #include "Tools.h"
  10.  
  11. #include <ErrorGlobals.h>
  12. #include <RsrcGlobals.h>
  13.  
  14. #include <Resources.h>
  15. #include <ToolUtils.h>
  16. #include <OSUtils.h>
  17. #include <Script.h>
  18.  
  19. #ifndef __STDIO__
  20. #include <stdio.h>
  21. #endif
  22.  
  23. #pragma segment MyComm
  24.  
  25. #define qDebugConstruct qDebug & 0
  26.  
  27.  
  28. PRealNntp::PRealNntp()
  29. {
  30. #if qDebugConstruct
  31.     fprintf(stderr, "PRealNntp::PRealNntp() at $%lx called\n", long(this));
  32. #endif
  33.     fPostingAllowed = false;
  34.     fCmdP = nil;
  35.     fAltCmdP = nil;
  36.     fAvoidListOfGroupDescriptions = false;
  37. }
  38.  
  39. void PRealNntp::IRealNntp(long newsServerAddr)
  40. {
  41. #if qDebugConstruct
  42.     fprintf(stderr, "void PRealNntp::IRealNntp() at $%lx called\n", long(this));
  43. #endif
  44.     INntp();
  45.     INetAsciiProtocol(newsServerAddr, gPrefs->GetShortPrefs('SvPo'));
  46.     FailInfo fi;
  47.     if (fi.Try())
  48.     {
  49.         fCmdP = NewPermPtr(kCommandBufferSize);
  50.         *fCmdP = 0;
  51.         fAltCmdP = NewPermPtr(kCommandBufferSize);
  52.         *fAltCmdP = 0;
  53.  
  54.         LogCommands("Opening real nntp\n");
  55.         
  56.     // grab the hello msg
  57.         GetRespondLine();
  58.         long errorNumber, respondCode;
  59.         if (sscanf(fRespondLineP, "gethostbyaddr: error %ld %ld", &errorNumber, &respondCode) == 2)
  60.         {
  61.             // bogous respond line from server (mac without dotname)
  62.             fRespondCode = short(respondCode);
  63.         }
  64.         if (fRespondCode == 502)  // access restriction or permission denied
  65.             FailOSErr(errNotAllowedToReadNews);
  66.         if (fRespondCode != 200 && fRespondCode != 201)
  67.             DoFailNntpError(fCmdP);
  68.         fPostingAllowed = (fRespondCode == 200);
  69.         if (strstr(fRespondLineP, "ANU"))
  70.             fAvoidListOfGroupDescriptions = true;
  71.         if (gPrefs->GetBooleanPrefs('AlAu'))
  72.             DoAuth();
  73.         fi.Success();
  74.     }
  75.     else // fail
  76.     {
  77.         delete this;
  78.         fi.ReSignal();
  79.     }
  80. }
  81.  
  82. PRealNntp::~PRealNntp()
  83. {
  84. #if qDebugConstruct
  85.     fprintf(stderr, "PRealNntp::~PRealNntp() at $%lx called\n", long(this));
  86. #endif
  87.     if (fCmdP && fAltCmdP && fRespondLineP) // say goodbye
  88.         SayGoodbye();
  89.     fCmdP = DisposeIfPtr(fCmdP);
  90.     fAltCmdP = DisposeIfPtr(fAltCmdP);
  91.     LogCommands("Closed real nntp\n");
  92. }
  93.  
  94. void PRealNntp::DoFailNntpError(char *cmd)
  95. {
  96. #if qDebug
  97.     fprintf(stderr, "PRealNntp::DoFailNntpError()\n");
  98.     fprintf(stderr, "-   command = %s\n", cmd);
  99.     fprintf(stderr, "-   respond code = %hd\n", fRespondCode);
  100.     fprintf(stderr, "-   respond line = '%s'\n", fRespondLineP);
  101. #else 
  102.     cmd = cmd; // pragma unused
  103. #endif
  104.     if (fRespondCode >= 190 && fRespondCode <= 199)
  105.         FailOSErr(errDebugOutput);
  106.     switch (fRespondCode)
  107.     {
  108.         case 400:                                                // service discontinued
  109.             {
  110.                 CStr255 tooManyString;
  111.                 MyGetIndString(tooManyString, kTooManyUsersRespond);
  112.                 if (strstr(fRespondLineP, tooManyString))
  113.                     FailOSErr(errTooManyUsers);
  114.             }
  115.             FailOSErr(errServiceAborted);
  116.         case 411:                                                // no such news group
  117.             FailOSErr(errNntpBadGroup);
  118.         case 412:                                                // no newsgroup has been selected
  119.             FailOSErr(errUnexpectedNntpError);
  120.         case 420:                                                // no current article has been selected
  121.             FailOSErr(errUnexpectedNntpError);
  122.         case 423:                                                // no such article number in this group
  123.             FailOSErr(errNoSuchArticle);
  124.         case 430:                                                // no such article found
  125.             FailOSErr(errNoSuchArticle);
  126.         case 440:                                                // posting not allowed
  127.             FailOSErr(errNotAllowedToPost);
  128.         case 441:                                                // posting failed
  129.             FailOSErr(errPostingFailed);
  130.         case 500:                                                // command not recognized
  131.             FailOSErr(errBadNntpServer);
  132.         case 501:                                                // command syntax error
  133.             FailOSErr(errBadNntpServer);
  134.         case 502:                                                // access restriction or permission denied
  135.             FailOSErr(errNntpPermissionDenied);
  136.         case 503:                                                // program fault - command not performed
  137.             FailOSErr(errNntpServerFailed);
  138.         default:
  139.             FailOSErr(errUnknownNntpError);
  140.     }
  141. }
  142.         
  143. void PRealNntp::DoSingleCommand(char *cmd)
  144. {
  145.     LogCommands(cmd);
  146.     LogCommands("\n");
  147.     SendCommand(cmd);
  148.     while (true)
  149.     {
  150.         GetRespondLine();
  151.         if (fRespondCode == 100)
  152.             continue;
  153.         if (fRespondCode >= 190 && fRespondCode <= 199) // debug output
  154.             continue;
  155.         break;
  156.     }
  157. }
  158.  
  159. void PRealNntp::DoAuth()
  160. {
  161.     CStr255 username, password;
  162.     FailInfo fi;
  163.     if (fi.Try())
  164.     {
  165.         GetUserNameAndPassword(username, password);
  166.         sprintf(fAltCmdP, "authinfo user %s", (char*)username);
  167.         BlockSet(Ptr(&username), sizeof(username), 0);
  168.         DoSingleCommand(fAltCmdP);
  169.         BlockSet(fAltCmdP, kCommandBufferSize, 0);
  170.         if (fRespondCode == 482) // 482 Authorization already completed
  171.         {
  172.             fi.Success();
  173.             return;
  174.         }
  175.         if (fRespondCode == 502) // 502 Authentication error
  176.         {
  177.             ForgetCurrentPassword();
  178.             FailOSErr(errBadPassword);
  179.         }
  180.         if (fRespondCode == 281) // 281 Authentication accepted
  181.         {
  182.             fi.Success();
  183.             return;
  184.         }
  185.         if (fRespondCode != 381) // 381 PASS required
  186.         {
  187.             ForgetCurrentPassword();
  188.             DoFailNntpError(fAltCmdP);
  189.         }
  190.         sprintf(fAltCmdP, "authinfo pass %s", (char*)password);
  191.         BlockSet(Ptr(&password), sizeof(password), 0);
  192.         DoSingleCommand(fAltCmdP);
  193.         BlockSet(fAltCmdP, kCommandBufferSize, 0);
  194.         if (fRespondCode == 502) // 502 Authentication error
  195.         {
  196.             ForgetCurrentPassword();
  197.             FailOSErr(errBadPassword);
  198.         }
  199.         if (fRespondCode != 281) // 281 Authentication accepted
  200.         {
  201.             ForgetCurrentPassword();
  202.             DoFailNntpError(fAltCmdP);
  203.         }
  204.         fi.Success();
  205.     }
  206.     else // fail
  207.     {
  208.         BlockSet(fAltCmdP, kCommandBufferSize, 0);
  209.         BlockSet(Ptr(&username), sizeof(username), 0);
  210.         BlockSet(Ptr(&password), sizeof(password), 0);
  211.         fi.ReSignal();
  212.     }
  213. }
  214.         
  215. void PRealNntp::DoCmd()
  216. {
  217.     DoSingleCommand(fCmdP);
  218.     if (fRespondCode == 480) // 480 Authentication required for command
  219.     {
  220.         DoAuth();
  221.         DoSingleCommand(fCmdP); // reissue command
  222.     }
  223. }
  224.         
  225. void PRealNntp::DoSetGroup(const CStr255 &name)
  226. {
  227.     sprintf(fCmdP, "group %s", (char*) name);
  228.     DoCmd();
  229.     if (fRespondCode == 502)  // access restriction or permission denied
  230.         FailOSErr(errNotAllowedToReadNews);
  231.     if (fRespondCode != 211) // n f l s group selected
  232.         DoFailNntpError(fCmdP);
  233.     long i1, i2, first, last;
  234.     if (sscanf(fRespondLineP, "%ld %ld %ld %ld", &i1, &i2, &first, &last) != 4)
  235.         FailOSErr(errBadNntpRespons);
  236.     fFirstArticleID = first;
  237.     fLastArticleID = last;
  238. }
  239.  
  240.  
  241. Handle PRealNntp::GetListOfAllGroups()
  242. {
  243.     strcpy(fCmdP, "list");
  244.     DoCmd();
  245.     if (fRespondCode != 215) // list of group follows
  246.         DoFailNntpError(fCmdP);
  247.     return GetDotTerminatedText();
  248. }
  249.  
  250.  
  251. Handle PRealNntp::GetListOfNewGroups(unsigned long fromDate)
  252. {
  253.     if (fromDate == 0) // 1904
  254.         return GetListOfAllGroups();
  255.     DateTimeRec dt;
  256.     Secs2Date(fromDate, dt);
  257.     MachineLocation loc;
  258.     ReadLocation(loc);
  259.     long gmt = dt.hour + 24 - short(loc.gmtFlags.gmtDelta & 0xFFFF) / 3600;
  260.     sprintf(fCmdP, "newgroups %02hd%02hd%02hd %02hd%02hd%02hd GMT",
  261.         dt.year%100, dt.month, dt.day, gmt % 24, dt.minute, dt.second);
  262.     DoCmd();
  263.     if (fRespondCode == 432) // list of new newsgroups unavaible
  264.         FailOSErr(errNoListOfNewGroups);
  265.     if (fRespondCode != 231) // list of new newsgroups follows
  266.         DoFailNntpError(fCmdP);
  267.     return GetDotTerminatedText();
  268. }
  269.  
  270.  
  271. Handle PRealNntp::GetListOfGroupDesciptions()
  272. {
  273.     if (fAvoidListOfGroupDescriptions)
  274.         return NewPermHandle(0);
  275.     strcpy(fCmdP, "list newsgroups");
  276.     DoCmd();
  277.     if (fRespondCode == 500) // command not recognized
  278.         return NewPermHandle(0);
  279.     if (fRespondCode == 501) // command syntax error
  280.         return NewPermHandle(0);
  281.     if (fRespondCode == 503) // No list of newsgroup descriptions available
  282.         return NewPermHandle(0);
  283.     if (fRespondCode != 215) // list of group follows
  284.         DoFailNntpError(fCmdP);
  285.     return GetDotTerminatedText();
  286. }
  287.  
  288.  
  289. Handle PRealNntp::GetHeaderList(const char *headerName, long firstArticleID, long lastArticleID)
  290. {
  291.     sprintf(fCmdP, "xhdr %s %ld-%ld", headerName, firstArticleID, lastArticleID);
  292.     DoCmd();
  293.     if (fRespondCode != 221) // xxxx fields follow
  294.         DoFailNntpError(fCmdP);
  295.     long oldProgress = gCurProgress->GetWork();
  296.     Handle h = nil;
  297.     VOLATILE(h);
  298.     FailInfo fi;
  299.     if (fi.Try())
  300.     {
  301.         h = GetDotTerminatedText();
  302.         gCurProgress->SetWorkDone(oldProgress + lastArticleID - firstArticleID + 1);
  303.         fi.Success();
  304.         return h;
  305.     }
  306.     else // fail
  307.     {
  308.         h = DisposeIfHandle(h);
  309.         fi.ReSignal();
  310.     }
  311. }
  312.  
  313.  
  314. Handle PRealNntp::GetArticle(long articleID)
  315. {
  316.     sprintf(fCmdP, "article %ld", articleID);
  317.     DoCmd();
  318.     if (fRespondCode != 220) // <a> Article retrieved; head and body follow.
  319.         DoFailNntpError(fCmdP);
  320.     return GetDotTerminatedText();
  321. }
  322.  
  323. void PRealNntp::SayGoodbye()
  324. {
  325.     FailInfo fi;
  326.     if (fi.Try())
  327.     {
  328.         sprintf(fCmdP, "quit");
  329.         // DoCmd() cannot be used as not response is sent
  330.         SendCommand(fCmdP); // so we just sends it
  331.         fi.Success();
  332.     }
  333.     else // fail
  334.     {
  335. #if qDebug
  336.         if (fi.error)
  337.             fprintf(stderr, "Got error when sending quit nntp command: %ld\n", long(fi.error));
  338. #endif
  339.         // don't care about errors when saying goodbye
  340.     }
  341. }
  342.  
  343. Boolean PRealNntp::IsPostingAllowed()
  344. {
  345.     return fPostingAllowed;
  346. }
  347.  
  348. void PRealNntp::PostArticle(Handle h, short ackStringID)
  349. {
  350.     if (!fPostingAllowed)
  351.         FailOSErr(errNotAllowedToPost);
  352.     gCurProgress->SetWorkToDo(kCandyStribes);
  353.     sprintf(fCmdP, "post");
  354.     DoCmd();
  355.     if (fRespondCode == 502) // access restriction or permission denied
  356.         FailOSErr(errNotAllowedToPost);
  357.     if (fRespondCode != 340) // 340 send article to be posted. End with <CR-LF>.<CR-LF>
  358.         DoFailNntpError(fCmdP);
  359.     gCurProgress->SetWorkToDo(GetHandleSize(h));
  360.     SendDotTerminatedText(h);
  361.     gCurProgress->SetWorkToDo(kCandyStribes);
  362.     gCurProgress->SetText(ackStringID);
  363.     GetRespondLine();
  364.     if (fRespondCode != 240) // 240 article posted ok
  365.         DoFailNntpError(fCmdP);
  366. }
  367.  
  368. void PRealNntp::ExamineNewsServer()
  369. {
  370.     Handle h = GetResource('STR#', kCheckServerGroupsStrings);
  371.     FailNILResource(h);
  372.     short noGroups = **( (short**) h);
  373.     Boolean foundGroup = false;
  374.     Boolean gotDeniedPermissionError = false;
  375.     long articleID;
  376.     for (short groupIndex = 1; groupIndex <= noGroups; groupIndex++)
  377.     {
  378.         CStr255 groupName;
  379.         GetIndString(groupName, kCheckServerGroupsStrings, groupIndex);
  380.         sprintf(fCmdP, "group %s", (char*) groupName);
  381.         DoCmd();
  382.         if (fRespondCode == 502) // access restriction or permission denied
  383.         {
  384.             LogCommands("Was not allowed to select the group, jumps to next group\n");
  385.             gotDeniedPermissionError = true;
  386.             continue; // it could be that single group
  387.         }
  388.         if (fRespondCode != 211) // n f l s group selected
  389.         {
  390.             LogCommands("Got non-211 respond code, jumps to next group\n");
  391.             continue;
  392.         }
  393.         long i1, i2, firstArticleID, lastArticleID;
  394.         if (sscanf(fRespondLineP, "%ld %ld %ld %ld", &i1, &i2, &firstArticleID, &lastArticleID) != 4) 
  395.         {
  396.             LogCommands("Problem with sscan of line\n");
  397.             FailOSErr(errBadNntpRespons);
  398.         }
  399.         if (firstArticleID > lastArticleID)
  400.         {
  401.             LogCommands("firstArticleID > lastArticleID, group is empty, jumps to next group\n");
  402.             continue; // empty group
  403.         }
  404.         foundGroup = true;
  405.         articleID = firstArticleID;
  406.         break;
  407.     }
  408.     if (!foundGroup)
  409.         if (gotDeniedPermissionError)
  410.             FailOSErr(errNotAllowedToReadNews);
  411.         else
  412.             FailOSErr(errNewsServerNoKnownGroups);
  413.  
  414.     sprintf(fCmdP, "xhdr Subject %ld-%ld", articleID, articleID);
  415.     DoCmd();
  416.     if (fRespondCode == 500) // command not recognized
  417.         FailOSErr(errMissingXHDRCommand);
  418.     if (fRespondCode != 221) // xxxx fields follow
  419.         DoFailNntpError(fCmdP);
  420.     h = GetDotTerminatedText();
  421.     h = DisposeIfHandle(h);
  422. }
  423.