home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / x / volume20 / xarchie / part08 < prev    next >
Encoding:
Text File  |  1993-06-14  |  50.4 KB  |  1,827 lines

  1. Newsgroups: comp.sources.x
  2. From: ferguson@cs.rochester.edu (George Ferguson)
  3. Subject: v20i036:  xarchie - An X browser interface to Archie, v2.0.6, Part08/24
  4. Message-ID: <1993Jun15.223253.370@sparky.imd.sterling.com>
  5. X-Md4-Signature: 4fed3aca02668e4d0f071088ca1a8b2a
  6. Sender: chris@sparky.imd.sterling.com (Chris Olson)
  7. Organization: Sterling Software
  8. Date: Tue, 15 Jun 1993 22:32:53 GMT
  9. Approved: chris@sparky.imd.sterling.com
  10.  
  11. Submitted-by: ferguson@cs.rochester.edu (George Ferguson)
  12. Posting-number: Volume 20, Issue 36
  13. Archive-name: xarchie/part08
  14. Environment: X11
  15. Supersedes: xarchie: Volume 14, Issue 82-90
  16.  
  17. Submitted-by: ferguson@cs.rochester.edu
  18. Archive-name: xarchie-2.0.6/part08
  19.  
  20. #!/bin/sh
  21. # this is Part.08 (part 8 of xarchie-2.0.6)
  22. # do not concatenate these parts, unpack them in order with /bin/sh
  23. # file xarchie-2.0.6/file-panel.c continued
  24. #
  25. if test ! -r _shar_seq_.tmp; then
  26.     echo 'Please unpack part 1 first!'
  27.     exit 1
  28. fi
  29. (read Scheck
  30.  if test "$Scheck" != 8; then
  31.     echo Please unpack part "$Scheck" next!
  32.     exit 1
  33.  else
  34.     exit 0
  35.  fi
  36. ) < _shar_seq_.tmp || exit 1
  37. if test ! -f _shar_wnt_.tmp; then
  38.     echo 'x - still skipping xarchie-2.0.6/file-panel.c'
  39. else
  40. echo 'x - continuing file xarchie-2.0.6/file-panel.c'
  41. sed 's/^X//' << 'SHAR_EOF' >> 'xarchie-2.0.6/file-panel.c' &&
  42. #include "db.h"
  43. #include "browser.h"
  44. #include "appres.h"
  45. #include "saveload.h"
  46. #include "file-panel.h"
  47. #include "fchooser.h"
  48. #include "status.h"
  49. #include "xutil.h"
  50. extern DbEntry *db;
  51. X
  52. /*
  53. X * Functions defined here
  54. X */
  55. void initFilePanelActions();
  56. void updateFileWriteMode();
  57. void setFileShellState();
  58. X
  59. static void fileSaveAction(),fileLoadAction(),fileWriteAction();
  60. static void popupFilePanel(),initFileWidgets();
  61. static void filePanelOk(),filePanelCancel();
  62. /*
  63. static FileChooserOkProc filePanelOk;
  64. static FileChooserCancelProc filePanelCancel;
  65. */
  66. static void writeModeWidgetsShown();
  67. X
  68. /*
  69. X * Data defined here
  70. X */
  71. static FileChooserInfo *fcinfo;
  72. static Widget fileShell,filePanelLabel;
  73. static Widget filePanelWriteModeButton,filePanelWriteModeLabel;
  74. static Boolean fileGoing,isPoppedUp;
  75. static int fileOp;
  76. X
  77. static XtActionsRec actionTable[] = {
  78. X    { "file-save",        fileSaveAction },
  79. X    { "file-load",        fileLoadAction },
  80. X    { "file-write",        fileWriteAction },
  81. };
  82. X
  83. void
  84. initFilePanelActions()
  85. {
  86. X    XtAppAddActions(appContext,actionTable,XtNumber(actionTable));
  87. }
  88. X
  89. /*    -    -    -    -    -    -    -    -    */
  90. /* Action Procedures */
  91. X
  92. #define ACTION_PROC(NAME)    void NAME(w,event,params,num_params) \
  93. X                    Widget w; \
  94. X                    XEvent *event; \
  95. X                    String *params; \
  96. X                    Cardinal *num_params;
  97. X
  98. /*ARGSUSED*/
  99. static
  100. ACTION_PROC(fileSaveAction)
  101. {
  102. X    popupFilePanel(FILE_SAVE);
  103. }
  104. X
  105. /*ARGSUSED*/
  106. static
  107. ACTION_PROC(fileLoadAction)
  108. {
  109. X    popupFilePanel(FILE_LOAD);
  110. }
  111. X
  112. /*ARGSUSED*/
  113. static
  114. ACTION_PROC(fileWriteAction)
  115. {
  116. X    popupFilePanel(FILE_WRITE);
  117. }
  118. X
  119. static void
  120. popupFilePanel(op)
  121. int op;
  122. {
  123. X    /* Ignore if the browser is being changed */
  124. X    if (getBrowserState() != BROWSER_READY) {
  125. X    XBell(display,0);
  126. X    return;
  127. X    }
  128. X    /* Create if this is the first time */
  129. X    if (fileShell == NULL) {
  130. X    setBusyStatus(True);
  131. X    initFileWidgets();
  132. X    setBusyStatus(False);
  133. X    }
  134. #ifdef FILECHOOSER
  135. X      else {
  136. X      status0("Re-initializing File Selector...");
  137. X      XfwfFileChooserRefresh((XfwfFileChooserWidget)(fcinfo->fcw));
  138. X    }
  139. #endif
  140. X    switch (op) {
  141. X    case FILE_SAVE:
  142. X        setWidgetLabel(filePanelLabel,"Save to file:");
  143. X        writeModeWidgetsShown(False);
  144. X        break;
  145. X    case FILE_LOAD:
  146. X        setWidgetLabel(filePanelLabel,"Load from file:");
  147. X        writeModeWidgetsShown(False);
  148. X        break;
  149. X    case FILE_WRITE:
  150. X        setWidgetLabel(filePanelLabel,"Write to file:");
  151. X        writeModeWidgetsShown(True);
  152. X        break;
  153. X    }
  154. X    fileOp = op;
  155. X    if (isPoppedUp) {
  156. X    XRaiseWindow(display,XtWindow(fileShell));
  157. X    } else {
  158. X    isPoppedUp = True;
  159. X    XtPopup(fileShell,XtGrabNone);
  160. X    }
  161. }
  162. X
  163. static void
  164. initFileWidgets()
  165. {
  166. X    Widget form;
  167. X    Arg args[1];
  168. X
  169. X    fileShell = XtCreatePopupShell("filePanelShell",topLevelShellWidgetClass,
  170. X                   toplevel,NULL,0);
  171. X    form = XtCreateManagedWidget("filePanelForm",formWidgetClass,
  172. X                 fileShell,NULL,0);
  173. X    filePanelLabel = XtCreateManagedWidget("filePanelLabel",labelWidgetClass,
  174. X                       form,NULL,0);
  175. X    filePanelWriteModeButton =
  176. X    XtCreateManagedWidget("filePanelWriteModeButton",menuButtonWidgetClass,
  177. X                  form,NULL,0);
  178. X    filePanelWriteModeLabel =
  179. X    XtCreateManagedWidget("filePanelWriteModeLabel",labelWidgetClass,
  180. X                  form,NULL,0);
  181. X    fcinfo = createFileChooser(fileShell,form,"filePanel",filePanelOk,
  182. X                   filePanelCancel,(XtPointer)fileShell);
  183. X    /* Adjust vertical layout */
  184. X    XtSetArg(args[0],XtNfromVert,filePanelWriteModeButton);
  185. #ifdef FILECHOOSER
  186. X    XtSetValues(fcinfo->fcw,args,1);
  187. #else
  188. X    XtSetValues(fcinfo->text,args,1);
  189. #endif
  190. X    /* Realize them all */
  191. X    XtRealizeWidget(fileShell);
  192. X    /* Register window for WM */
  193. X    (void)XSetWMProtocols(XtDisplay(fileShell),XtWindow(fileShell),
  194. X              &WM_DELETE_WINDOW,1);
  195. X    updateFileWriteMode(appResources.fileWriteOnePerLine);
  196. }
  197. X
  198. static void
  199. writeModeWidgetsShown(state)
  200. Boolean state;
  201. {
  202. X    if (state) {
  203. X    XtMapWidget(filePanelWriteModeButton);
  204. X    XtMapWidget(filePanelWriteModeLabel);
  205. X    } else {
  206. X    XtUnmapWidget(filePanelWriteModeButton);
  207. X    XtUnmapWidget(filePanelWriteModeLabel);
  208. X    }
  209. }
  210. X
  211. void
  212. setFileShellState(state)
  213. int state;
  214. {
  215. X    if (!isPoppedUp)
  216. X    return;
  217. X    switch (state) {
  218. X    case NormalState:
  219. X        XtMapWidget(fileShell);
  220. X        break;
  221. X    case IconicState:
  222. X        XtUnmapWidget(fileShell);
  223. X        break;
  224. X    }
  225. }
  226. X
  227. /*    -    -    -    -    -    -    -    -    */
  228. /* Callbacks from the FileChooser */
  229. X
  230. /*ARGSUSED*/
  231. static void
  232. filePanelOk(fcinfo,filename,client_data)
  233. FileChooserInfo *fcinfo;
  234. char *filename;
  235. XXtPointer client_data;        /* shell Widget */
  236. {
  237. X    Widget shell = (Widget)client_data;
  238. X    int status;
  239. X
  240. X    if (fileGoing) {
  241. X    XBell(display,0);
  242. X    return;
  243. X    }
  244. X    fileGoing = True;
  245. X    switch (fileOp) {
  246. X    case FILE_SAVE:
  247. X        status = save(db,filename);
  248. X        break;
  249. X    case FILE_LOAD:
  250. X        status = load(db,filename);
  251. X        break;
  252. X    case FILE_WRITE:
  253. X        status = writeToFile(db,filename,appResources.fileWriteOnePerLine);
  254. X        break;
  255. X    }
  256. X    fileGoing = False;
  257. X    if (status) {
  258. X    XtPopdown(shell);
  259. X    isPoppedUp = False;
  260. X    }
  261. }
  262. X
  263. /*ARGSUSED*/
  264. static void
  265. filePanelCancel(fcinfo,client_data)
  266. FileChooserInfo *fcinfo;
  267. XXtPointer client_data;        /* shell Widget */
  268. {
  269. X    Widget shell = (Widget)client_data;
  270. X
  271. X    if (fileGoing) {
  272. X    XBell(display,0);
  273. X    return;
  274. X    }
  275. X    XtPopdown(shell);
  276. X    isPoppedUp = False;
  277. }
  278. X
  279. /*    -    -    -    -    -    -    -    -    */
  280. /* Used by the menus */
  281. X
  282. void
  283. updateFileWriteMode(flag)
  284. Boolean flag;
  285. {
  286. X    if (flag)
  287. X    setWidgetLabel(filePanelWriteModeLabel,"One entry per line");
  288. X    else
  289. X    setWidgetLabel(filePanelWriteModeLabel,"Pretty-printed");
  290. }
  291. SHAR_EOF
  292. echo 'File xarchie-2.0.6/file-panel.c is complete' &&
  293. chmod 0644 xarchie-2.0.6/file-panel.c ||
  294. echo 'restore of xarchie-2.0.6/file-panel.c failed'
  295. Wc_c="`wc -c < 'xarchie-2.0.6/file-panel.c'`"
  296. test 5892 -eq "$Wc_c" ||
  297.     echo 'xarchie-2.0.6/file-panel.c: original size 5892, current size' "$Wc_c"
  298. rm -f _shar_wnt_.tmp
  299. fi
  300. # ============= xarchie-2.0.6/file-panel.h ==============
  301. if test -f 'xarchie-2.0.6/file-panel.h' -a X"$1" != X"-c"; then
  302.     echo 'x - skipping xarchie-2.0.6/file-panel.h (File already exists)'
  303.     rm -f _shar_wnt_.tmp
  304. else
  305. > _shar_wnt_.tmp
  306. echo 'x - extracting xarchie-2.0.6/file-panel.h (Text)'
  307. sed 's/^X//' << 'SHAR_EOF' > 'xarchie-2.0.6/file-panel.h' &&
  308. /*
  309. X * file-panel.h : Defs for the save-load-write panel
  310. X *
  311. X * George Ferguson, ferguson@cs.rochester.edu, 23 Apr 1993.
  312. X */
  313. X
  314. #ifndef FILE_PANEL_H
  315. #define FILE_PANEL_H
  316. X
  317. #define FILE_SAVE  1
  318. #define FILE_LOAD  2
  319. #define FILE_WRITE 3
  320. X
  321. extern void initFilePanelActions();
  322. extern void updateFileWriteMode();
  323. extern void setFileShellState();
  324. X
  325. #endif
  326. SHAR_EOF
  327. chmod 0644 xarchie-2.0.6/file-panel.h ||
  328. echo 'restore of xarchie-2.0.6/file-panel.h failed'
  329. Wc_c="`wc -c < 'xarchie-2.0.6/file-panel.h'`"
  330. test 343 -eq "$Wc_c" ||
  331.     echo 'xarchie-2.0.6/file-panel.h: original size 343, current size' "$Wc_c"
  332. rm -f _shar_wnt_.tmp
  333. fi
  334. # ============= xarchie-2.0.6/ftp-actions.c ==============
  335. if test -f 'xarchie-2.0.6/ftp-actions.c' -a X"$1" != X"-c"; then
  336.     echo 'x - skipping xarchie-2.0.6/ftp-actions.c (File already exists)'
  337.     rm -f _shar_wnt_.tmp
  338. else
  339. > _shar_wnt_.tmp
  340. echo 'x - extracting xarchie-2.0.6/ftp-actions.c (Text)'
  341. sed 's/^X//' << 'SHAR_EOF' > 'xarchie-2.0.6/ftp-actions.c' &&
  342. /*
  343. X * ftp-actions.c : X/FTP interface routines for xarchie
  344. X *
  345. X * George Ferguson, ferguson@cs.rochester.edu, 23 Apr 1993.
  346. X * 13 May 1993: Check for NULL return from ftpNewContext().
  347. X */
  348. X
  349. #include <stdio.h>
  350. #include <fcntl.h>            /* O_RDONLY, etc. */
  351. #include <X11/Intrinsic.h>
  352. #include <X11/Shell.h>
  353. #include <X11/StringDefs.h>
  354. #include <X11/Xaw/Form.h>
  355. #include <X11/Xaw/Command.h>
  356. #include <X11/Xaw/AsciiText.h>
  357. #include <X11/Xaw/Dialog.h>
  358. #include "config.h"
  359. #ifdef HAVE_SYS_PARAM_H
  360. #include <sys/param.h>
  361. #endif
  362. #include "db.h"
  363. #include "appres.h"
  364. #include "xarchie.h"
  365. #include "selection.h"
  366. #include "browser.h"
  367. #include "ftp.h"
  368. #include "view-file.h"
  369. #include "status.h"
  370. #include "popups.h"
  371. #include "xutil.h"
  372. #include "alert.h"
  373. #include "syserr.h"
  374. #include "debug.h"
  375. X
  376. /*
  377. X * Functions defined here
  378. X */
  379. void initFtpActions();
  380. void ftpGetSelectedItems(),ftpOpenSelectedItems();
  381. void RegisterFtpFd(),UnregisterFtpFd();
  382. int ftpPrompt();
  383. X
  384. static void ftpSelectedItems(),countFileToGet(),countFileToOpen(),addFile();
  385. static void ftpGetFinished(),ftpOpenOneFinished();
  386. static void initFtpTraceWidgets();
  387. static void ftpTraceDoneAction();
  388. static void ftpTraceReset(),ftpTraceFunc();
  389. static void inputCallback();
  390. static void ftpPromptCallback();
  391. X
  392. /*
  393. X * Data defined here
  394. X */
  395. static char **ftpFilenames;
  396. static int numFtpFiles;
  397. static FtpContext *ftpCurrentContext;
  398. X
  399. static Widget ftpTraceShell,ftpTraceText;
  400. static Boolean isPoppedUp;
  401. X
  402. static XtActionsRec actionTable[] = {
  403. X    { "ftp-trace-done",    ftpTraceDoneAction },
  404. };
  405. X
  406. /*    -    -    -    -    -    -    -    -    */
  407. /* Interface functions */
  408. X
  409. void
  410. initFtpActions()
  411. {
  412. X    XtAppAddActions(appContext,actionTable,XtNumber(actionTable));
  413. }
  414. X
  415. void
  416. ftpGetSelectedItems()        /* Called from getAction() */
  417. {
  418. X    ftpSelectedItems(appResources.ftpLocalDir,appResources.ftpType,
  419. X             appResources.ftpPrompt,appResources.ftpStrip,
  420. X             countFileToGet,NULL,ftpGetFinished);
  421. }
  422. X
  423. void
  424. ftpOpenSelectedItems()        /* Called from openBrowser() */
  425. {
  426. X    ftpSelectedItems(tmpDirectory,"ascii",False,True,
  427. X             countFileToOpen,ftpOpenOneFinished,ftpGetFinished);
  428. }
  429. X
  430. void
  431. ftpAbortTransfer()
  432. {
  433. X    DEBUG1("ftpAbortTransfer: ftpCurrentContext=0x%x\n",ftpCurrentContext);
  434. X    ftpAbort(ftpCurrentContext);
  435. X    DEBUG0("ftpAbortTransfer: done\n");
  436. }
  437. X
  438. /*    -    -    -    -    -    -    -    -    */
  439. /*
  440. X * This function starts ftp retrieval of the items selected in the
  441. X * browser into the local directory.
  442. X */
  443. static void
  444. ftpSelectedItems(local_dir,typestr,prompt,strip,
  445. X         countProc,doneOneProc,doneAllProc)
  446. char *local_dir,*typestr;
  447. Boolean prompt,strip;
  448. void (*countProc)();
  449. FtpCallbackProc doneOneProc,doneAllProc;
  450. {
  451. X    char *host,*cwd;
  452. X    int type;
  453. #ifdef DEBUG
  454. X    int i;
  455. #endif
  456. X
  457. X    DEBUG0("ftpSelectedItems: setting files to transfer\n");
  458. X    numFtpFiles = 0;
  459. X    forEachSelectedItem(countProc);
  460. X    if (numFtpFiles == 0) {
  461. X    return;
  462. X    }
  463. X    ftpFilenames = (char **)XtCalloc(numFtpFiles,sizeof(char *));
  464. X    numFtpFiles = 0;
  465. X    forEachSelectedItem(addFile);
  466. #ifdef DEBUG
  467. X    for (i=0; i < numFtpFiles; i++)
  468. X    fprintf(stderr,"ftpSelectedItems: ftpFilenames[%d] = \"%s\"\n",
  469. X        i,ftpFilenames[i]);
  470. #endif
  471. X    /* Is there a host? */
  472. X    if ((host=getWidgetString(hostText)) == NULL || *host == '\0') {
  473. X    alert0("No host specified for transfer!");
  474. X    return;
  475. X    }
  476. X    DEBUG1("ftpSelectedItems: host = \"%s\"\n",host);
  477. X    /* Optional remote directory */
  478. X    cwd = getWidgetString(locationText); /* Can be "" */
  479. X    DEBUG1("ftpSelectedItems: remote dir = \"%s\"\n",cwd);
  480. X    if (cwd && *cwd == '\0')
  481. X    cwd = NULL;
  482. X    /* Convert type to ARPA code */
  483. X    if (typestr == NULL || *typestr == 'a' || *typestr == 'A')
  484. X    type = TYPE_A;
  485. X    else if (*typestr == 'b' || *typestr == 'B')
  486. X    type = TYPE_I;
  487. X    else if (*typestr == 'e' || *typestr == 'E')
  488. X    type = TYPE_E;
  489. X    else
  490. X    type = atoi(typestr);
  491. X    /* Put up the tracing window if needed */
  492. X    if (appResources.ftpTrace) {
  493. X    if (ftpTraceShell == NULL)
  494. X        initFtpTraceWidgets();
  495. X    ftpTraceReset();
  496. X    isPoppedUp = True;
  497. X    XtPopup(ftpTraceShell,XtGrabNone);
  498. X    }
  499. X    /* Get the FTP context */
  500. X    ftpCurrentContext =
  501. X    ftpNewContext(host,"anonymous",appResources.ftpMailAddress,
  502. X              cwd,local_dir,type,strip,(numFtpFiles>1 && prompt),
  503. X              FTP_GET,ftpFilenames,numFtpFiles,
  504. X              (appResources.ftpTrace ? ftpTraceFunc : NULL),
  505. X              doneOneProc,doneAllProc);
  506. X    XtFree((char *)ftpFilenames);
  507. X    /* Hostname lookup might have failed */
  508. X    if (ftpCurrentContext == NULL)
  509. X    return;
  510. X    /* Here we go... */
  511. X    setBrowserState(BROWSER_FTP);
  512. X    ftpStart(ftpCurrentContext);
  513. X    DEBUG0("ftpSelectedItems: done\n");
  514. }
  515. X
  516. /*    -    -    -    -    -    -    -    -    */
  517. /* Functions called by ftpGetSelectedItems */
  518. X
  519. /*ARGSUSED*/
  520. static void
  521. countFileToGet(dbp,list_index)        /* complains about non-files */
  522. DbEntry *dbp;
  523. int list_index;
  524. {
  525. X    if (dbp->type == DB_FILE) {
  526. X    numFtpFiles += 1;
  527. X    } else {
  528. X    alert1("Can't retrieve non-file \"%s\".",dbp->name);
  529. X    }
  530. }
  531. X
  532. /*ARGSUSED*/
  533. static void
  534. countFileToOpen(dbp,list_index)        /* doesn't complain about non-files */
  535. DbEntry *dbp;
  536. int list_index;
  537. {
  538. X    if (dbp->type == DB_FILE) {
  539. X    numFtpFiles += 1;
  540. X    }
  541. }
  542. X
  543. /*ARGSUSED*/
  544. static void
  545. addFile(dbp,list_index)            /* adds filename to array */
  546. DbEntry *dbp;
  547. int list_index;
  548. {
  549. X    if (dbp->type == DB_FILE) {
  550. X    ftpFilenames[numFtpFiles++] = XtNewString(dbp->name);
  551. X    }
  552. }
  553. X
  554. /*    -    -    -    -    -    -    -    -    */
  555. /* FTP callbacks */
  556. X
  557. /*
  558. X * This function is called back when the ftp transfer is complete (for
  559. X * whatever reason).
  560. X */
  561. /*ARGUSED*/
  562. static void
  563. ftpGetFinished(ftpc)
  564. FtpContext *ftpc;
  565. {
  566. X    DEBUG1("ftpGetFinished(0x%x)...\n",ftpc);
  567. X    setBrowserState(BROWSER_READY);
  568. X    ftpFreeContext(ftpc);
  569. X    status0("Ready");
  570. X    DEBUG0("ftpGetFinished: done\n");
  571. }
  572. X
  573. /*
  574. X * This function is called back when a single file has been successfully
  575. X * retrieved for Open.
  576. X */
  577. /*ARGSUSED*/
  578. static void
  579. ftpOpenOneFinished(ftpc)
  580. FtpContext *ftpc;
  581. {
  582. X    char filename[MAXPATHLEN];
  583. X
  584. X    DEBUG1("ftpOpenOneFinished(0x%x)...\n",ftpc);
  585. X    if (ftpc->local_dir && *(ftpc->local_dir))
  586. X    sprintf(filename,"%s/%s",ftpc->local_dir,ftpc->files[ftpc->this_file]);
  587. X    else
  588. X    strcpy(filename,ftpc->files[ftpc->this_file]);
  589. X    viewFile(filename);
  590. X    DEBUG0("ftpOpenOneFinished: done\n");
  591. }
  592. X
  593. /*    -    -    -    -    -    -    -    -    */
  594. /* Routines for tracing the ftp connection in a window */
  595. X
  596. static void
  597. initFtpTraceWidgets()
  598. {
  599. X    Widget form;
  600. X
  601. X    ftpTraceShell = XtCreatePopupShell("ftpTraceShell",
  602. X                       topLevelShellWidgetClass,
  603. X                       toplevel,NULL,0);
  604. X    form = XtCreateManagedWidget("ftpTraceForm",formWidgetClass,
  605. X                 ftpTraceShell,NULL,0);
  606. X    (void)XtCreateManagedWidget("ftpTraceDismissButton",commandWidgetClass,
  607. X                form,NULL,0);
  608. X    ftpTraceText = XtCreateManagedWidget("ftpTraceText",asciiTextWidgetClass,
  609. X                     form,NULL,0);
  610. X    XtRealizeWidget(ftpTraceShell);
  611. X    (void)XSetWMProtocols(XtDisplay(ftpTraceShell),XtWindow(ftpTraceShell),
  612. X              &WM_DELETE_WINDOW,1);
  613. }
  614. X
  615. void
  616. setFtpTraceShellState(state)
  617. int state;
  618. {
  619. X    if (!isPoppedUp)
  620. X    return;
  621. X    switch (state) {
  622. X    case NormalState:
  623. X        XtMapWidget(ftpTraceShell);
  624. X        break;
  625. X    case IconicState:
  626. X        XtUnmapWidget(ftpTraceShell);
  627. X        break;
  628. X    }
  629. }
  630. X
  631. /*ARGSUSED*/
  632. static void
  633. ftpTraceDoneAction(w,event,params,num_params)
  634. Widget w;
  635. XXEvent *event;
  636. String *params;
  637. Cardinal *num_params;
  638. {
  639. X    isPoppedUp = False;
  640. X    XtPopdown(ftpTraceShell);
  641. }
  642. X
  643. static void
  644. ftpTraceReset()
  645. {
  646. X    Arg args[1];
  647. X
  648. X    XtSetArg(args[0],XtNstring,"");
  649. X    XtSetValues(ftpTraceText,args,1);
  650. }
  651. X
  652. /*
  653. X * This function is called back from within the ftp routines to monitor
  654. X * the exchange of messages.
  655. X */
  656. /*ARGSUSED*/
  657. static void
  658. ftpTraceFunc(ftpc,who,text)
  659. FtpContext *ftpc;
  660. int who;        /* 0 => recvd, non-0 => sent */
  661. char *text;        /* text of this message */
  662. {
  663. X    if (who)
  664. X    appendWidgetText(ftpTraceText,"ftp> ");
  665. X    appendWidgetText(ftpTraceText,text);
  666. X    if (*(text+strlen(text)-1) != '\n')
  667. X    appendWidgetText(ftpTraceText,"\n");
  668. }
  669. X
  670. /*    -    -    -    -    -    -    -    -    */
  671. /* File descriptor registration routines: */
  672. X
  673. /*
  674. X * We need as many of these as there are file descriptors. It's
  675. X * easier to guess big than to figure out where such a magic number lives.
  676. X */
  677. #define NUMFDS 64
  678. FtpCallbackProc ftpRegisteredProcs[NUMFDS];
  679. FtpContext *ftpRegisteredContexts[NUMFDS];
  680. XXtInputId ftpRegisteredIds[NUMFDS];
  681. X
  682. /*
  683. X * This function is exported and used by the FTP routines to register
  684. X * a file descriptor for notification. We register it by recording the
  685. X * callback information (proc and ftpc) and telling X to register the
  686. X * fd as an external input source. When X calls back to inputCallback(),
  687. X * we use the stored information to call back to the FTP routine.
  688. X * Got that?
  689. X */
  690. void
  691. RegisterFtpFd(ftpc,fd,flags,proc)
  692. FtpContext *ftpc;
  693. int fd,flags;
  694. FtpCallbackProc proc;
  695. {
  696. X    XtInputMask condition;
  697. X
  698. X    DEBUG3("RegisterFtpFd: ftpc=0x%x, fd=%d, flags=%d\n",ftpc,fd,flags);
  699. X    if (fd < 0 || fd >= NUMFDS) {
  700. X    fprintf(stderr,"YOW! Attempt to register fd %d!\n",fd);
  701. #ifdef DEBUG
  702. X    abort();
  703. #endif
  704. X    return;
  705. X    }
  706. X    switch (flags) {
  707. X      case O_RDONLY:
  708. X    condition = XtInputReadMask;
  709. X    break;
  710. X      case O_WRONLY:
  711. X    condition = XtInputWriteMask;
  712. X    break;
  713. X      case O_RDWR:
  714. X    condition = XtInputReadMask | XtInputWriteMask;
  715. X    break;
  716. X    }
  717. X    ftpRegisteredProcs[fd] = proc;
  718. X    ftpRegisteredContexts[fd] = ftpc;
  719. X    ftpRegisteredIds[fd] =
  720. X    XtAppAddInput(appContext,fd,(XtPointer)condition,inputCallback,NULL);
  721. X    DEBUG1("RegisterFtpFd: done: id=0x%x\n",ftpRegisteredIds[fd]);
  722. }
  723. X
  724. /*
  725. X * Called back when X says source is ready. We call the function registered
  726. X * by the FTP routines, passing the context.
  727. X */
  728. /*ARGSUSED*/
  729. static void
  730. inputCallback(client_data,source,id)
  731. XXtPointer client_data;
  732. int *source;
  733. XXtInputId *id;
  734. {
  735. X    if (ftpRegisteredProcs[*source] != NULL) {
  736. X    (*(ftpRegisteredProcs[*source]))(ftpRegisteredContexts[*source]);
  737. X    } else {
  738. X    fprintf(stderr,"YOW! Callback for fd=%d not registered!\n",*source);
  739. #ifdef DEBUG
  740. X    abort();
  741. #endif
  742. X    }
  743. }
  744. X
  745. /*
  746. X * This function is exported and used by the FTP routines to undo
  747. X * a previous registration.
  748. X */
  749. /*ARGSUSED*/
  750. void
  751. UnregisterFtpFd(ftpc,fd)
  752. FtpContext *ftpc;
  753. int fd;
  754. {
  755. X    DEBUG3("UnregisterFtpFd: ftpc=0x%x, fd=%d, id=0x%x\n",
  756. X       ftpc,fd,ftpRegisteredIds[fd]);
  757. X    if (fd < 0 || fd >= NUMFDS) {
  758. X    fprintf(stderr,"YOW! Attempt to unregister fd %d!\n",fd);
  759. #ifdef DEBUG
  760. X    abort();
  761. #endif
  762. X    return;
  763. X    }
  764. X    if (ftpRegisteredIds[fd] != (XtInputId)NULL)
  765. X    XtRemoveInput(ftpRegisteredIds[fd]);
  766. X    ftpRegisteredIds[fd] = (XtInputId)NULL;
  767. X    ftpRegisteredProcs[fd] = NULL;
  768. X    ftpRegisteredContexts[fd] = NULL;
  769. X    DEBUG0("UnregisterFtpFd: done\n");
  770. }
  771. X
  772. /*    -    -    -    -    -    -    -    -    */
  773. /* Routines for prompting during FTP transfers: */
  774. X
  775. static Widget ftpPromptShell;
  776. static int ftpPromptResult;
  777. X
  778. int
  779. ftpPrompt(ftpc)
  780. FtpContext *ftpc;
  781. {
  782. X    char str[256];
  783. X
  784. X    if (ftpPromptShell == NULL)
  785. X    ftpPromptShell = createPopup("ftpPrompt",4,ftpPromptCallback);
  786. X    sprintf(str,"%s %s?",
  787. X        (ftpc->filecmd==FTP_GET?"GET":"PUT"),ftpc->files[ftpc->this_file]);
  788. X    setPopupLabel(ftpPromptShell,"ftpPrompt",str);
  789. X    popupMainLoop(ftpPromptShell);
  790. X    return(ftpPromptResult);
  791. }
  792. /*ARGSUSED*/
  793. static void
  794. ftpPromptCallback(w,client_data,call_data)
  795. Widget w;
  796. XXtPointer client_data;        /* button number */
  797. XXtPointer call_data;
  798. {
  799. X    switch ((int)client_data) {
  800. X      case 0:            /* Yes */
  801. X    ftpPromptResult = 1;
  802. X    break;
  803. X      case 1:            /* No */
  804. X    ftpPromptResult = 0;
  805. X    break;
  806. X      case 2:            /* All */
  807. X    ftpCurrentContext->prompt = 0;
  808. X    ftpPromptResult = 1;
  809. X    break;
  810. X      case 3:            /* Abort */
  811. X    ftpCurrentContext->this_file = ftpCurrentContext->num_files;
  812. X    ftpPromptResult = 0;
  813. X    break;
  814. X    }
  815. X    popupDone();
  816. }
  817. SHAR_EOF
  818. chmod 0644 xarchie-2.0.6/ftp-actions.c ||
  819. echo 'restore of xarchie-2.0.6/ftp-actions.c failed'
  820. Wc_c="`wc -c < 'xarchie-2.0.6/ftp-actions.c'`"
  821. test 11489 -eq "$Wc_c" ||
  822.     echo 'xarchie-2.0.6/ftp-actions.c: original size 11489, current size' "$Wc_c"
  823. rm -f _shar_wnt_.tmp
  824. fi
  825. # ============= xarchie-2.0.6/ftp-actions.h ==============
  826. if test -f 'xarchie-2.0.6/ftp-actions.h' -a X"$1" != X"-c"; then
  827.     echo 'x - skipping xarchie-2.0.6/ftp-actions.h (File already exists)'
  828.     rm -f _shar_wnt_.tmp
  829. else
  830. > _shar_wnt_.tmp
  831. echo 'x - extracting xarchie-2.0.6/ftp-actions.h (Text)'
  832. sed 's/^X//' << 'SHAR_EOF' > 'xarchie-2.0.6/ftp-actions.h' &&
  833. /*
  834. X * ftp-actions.h : Defs for yet another layer of the ftp routines
  835. X *
  836. X * George Ferguson, ferguson@cs.rochester.edu, 23 Apr 1993.
  837. X */
  838. X
  839. extern void initFtpActions();
  840. extern void ftpGetSelectedItems(),ftpOpenSelectedItems();
  841. extern void setFtpTraceShellState();
  842. SHAR_EOF
  843. chmod 0644 xarchie-2.0.6/ftp-actions.h ||
  844. echo 'restore of xarchie-2.0.6/ftp-actions.h failed'
  845. Wc_c="`wc -c < 'xarchie-2.0.6/ftp-actions.h'`"
  846. test 262 -eq "$Wc_c" ||
  847.     echo 'xarchie-2.0.6/ftp-actions.h: original size 262, current size' "$Wc_c"
  848. rm -f _shar_wnt_.tmp
  849. fi
  850. # ============= xarchie-2.0.6/ftp.c ==============
  851. if test -f 'xarchie-2.0.6/ftp.c' -a X"$1" != X"-c"; then
  852.     echo 'x - skipping xarchie-2.0.6/ftp.c (File already exists)'
  853.     rm -f _shar_wnt_.tmp
  854. else
  855. > _shar_wnt_.tmp
  856. echo 'x - extracting xarchie-2.0.6/ftp.c (Text)'
  857. sed 's/^X//' << 'SHAR_EOF' > 'xarchie-2.0.6/ftp.c' &&
  858. /*
  859. X * ftp.c : This code implements an asynchronous ftp client.
  860. X *
  861. X * George Ferguson, ferguson@cs.rochester.edu, 23 Apr 1993.
  862. X *
  863. X * The client is represented by an instance of the FtpContext structure,
  864. X * which includes the state of the client with respect to a finite-state
  865. X * model of the FTP process. All aspects of the connection are contained
  866. X * in the structure, so a process can have multiple outstanding FTP
  867. X * sessions (subject to filesystem limitations, of course).
  868. X *
  869. X * Refer to RFC959 for details of the state model.
  870. X *
  871. X * Two external functions must be provided:
  872. X *   void RegisterFtpFd( ftpc, fd, flags, func )
  873. X *      Should arrange to call FUNC passing FTPC whenever FD is ready
  874. X *      as indicated by FLAGS (from <fcntl.h>).
  875. X *   void UnregisterFtpFd( ftpc, fd )
  876. X *      Cancels a previous registration of FD for FTPC.
  877. X * Samples of these using select(2) are given below in the STANDALONE
  878. X * section. Xarchie uses the XtAppAddInput() mechanism. The code also
  879. X * uses alert0() and status0() for messages, sysError() for error
  880. X * messages from system calls, and ftpPrompt() if prompting is enabled.
  881. X *
  882. X * To use these routines:
  883. X *   ftpc = ftpNewContext(...);
  884. X *   ftpStart(ftpc);
  885. X * The function you registered as the "done" parameter in ftpNewContext
  886. X * will be called back when the process finishes (for any reason). You
  887. X * should call ftpFreeContext() in this callback (or register it as the
  888. X * callback, or register NULL).
  889. X *
  890. X * This code is decidely *not* a general-purpose FTP library. It is
  891. X * designed to support the batch transfers required by xarchie. I suppose
  892. X * that it could be modified to be more general without too much effort.
  893. X * In particular, many of the routines called by ftpProcessReply could
  894. X * be made into external interface functions. Volunteers?
  895. X *
  896. X * 28 Apr 1993: Status mesage for bytes transferred was backwards.
  897. X *  1 Jun 1993: Fixes for ISC. Are these needed for other SYS5?
  898. X */
  899. #include <stdio.h>
  900. #include <errno.h>
  901. #include "config.h"
  902. #ifdef HAVE_SYS_PARAM_H
  903. #include <sys/param.h>
  904. #endif
  905. #include "ftp.h"    /* includes <sys/types.h> and <netinet/in.h> */
  906. #include "sysdefs.h"    /* char *malloc() */
  907. #include "stringdefs.h" /* char *strcpy(), *index(); */
  908. #include "debug.h"    /* MSG[0-3]() macros */
  909. X
  910. /* These functions have to be provided: */
  911. extern void RegisterFtpFd(/* ftpc, fd, O_RDWR | O_RDONLY, func */);
  912. extern void UnregisterFtpFd(/* ftpc, fd */);
  913. extern int ftpPrompt(/* ftpc */);
  914. extern void status0(/* str */);
  915. extern void alert0(/* str */);
  916. extern void sysError(/* str */);
  917. X
  918. /*
  919. X * Portable non-blocking I/O macros, I hope.
  920. X *   hp300 : From Andy.Linton@comp.vuw.ac.nz
  921. X *   sgi   : From amoss@cs.huji.ac.il
  922. X */
  923. #if defined(hp300)
  924. X  /* Here's for BSD, maybe, but Sys5 can't tell this from EOF. */
  925. # include <fcntl.h>
  926. # define MAKE_NONBLOCKING(fd) fcntl(fd,F_SETFL,O_NDELAY)
  927. # define ITWOULDBLOCK EWOULDBLOCK
  928. #else
  929. #if defined(sgi)
  930. # include <fcntl.h>
  931. # define MAKE_NONBLOCKING(fd) fcntl(fd,F_SETFL,O_NONBLOCK)
  932. # define ITWOULDBLOCK EWOULDBLOCK
  933. #else
  934. X  /* This is POSIX, the default, which uses EAGAIN. */
  935. # include <fcntl.h>
  936. # define MAKE_NONBLOCKING(fd) fcntl(fd,F_SETFL,O_NONBLOCK)
  937. # define ITWOULDBLOCK EAGAIN
  938. #endif
  939. #endif
  940. /*
  941. X * Networking includes from Brendan Kehoe (dirsend.c)
  942. X */
  943. #include <netdb.h>
  944. #include <sys/socket.h>
  945. #ifndef hpux
  946. # include <arpa/inet.h>
  947. #endif
  948. /* Interactive UNIX keeps some of the socket definitions in funny places.  */
  949. #ifdef ISC
  950. # include <net/errno.h>        /* I wonder about this... */
  951. #endif /* ISC */
  952. X
  953. #ifndef IPPORT_FTP
  954. #define IPPORT_FTP 21        /* From <netinet/in.h> */
  955. #endif
  956. X
  957. #define NewString(S)        strcpy(malloc(strlen(S)+1),S)
  958. #define ftpfilecmdstr(X)    ((X)==FTP_GET ? "GET" : "PUT")
  959. X
  960. /*
  961. X * Functions defined here:
  962. X */
  963. FtpContext *ftpNewContext();
  964. void ftpStart(),ftpAbort();
  965. void ftpFreeContext();
  966. X
  967. /* Initialization */
  968. static int ftpGetHostAndPort();
  969. /* Connection establishment */
  970. static void ftpConnectCallback();
  971. static int ftpGetSocket(),ftpConnect();
  972. /* Reading server replies */
  973. static void ftpInitReply(),ftpReplyCallback();
  974. /* Main FTP client state-machine */
  975. static void ftpProcessReply();
  976. static void ftpAlert(),ftpHandleErrorThenQuit(),ftpDone();
  977. static void ftpSendType(),ftpSendNextCwd();
  978. static int ftpSendPort();
  979. static void ftpSendGetPut();
  980. static int ftpAcceptDataConn(),ftpSetupLocalData();
  981. /* Data connection processing */
  982. static void ftpDataCallback();
  983. static void ftpReadData(),ftpWriteData(),ftpCleanupDataConn();
  984. /* Sending commands to the server */
  985. static void ftpStartSendingCmd(),ftpWriteCallback();
  986. static void ftpSendCmd(),ftpSendAbort();
  987. #ifdef DEBUG
  988. char *ftpstatestr();
  989. #endif
  990. X
  991. /*    -    -    -    -    -    -    -    -    */
  992. /* Exported functions: */
  993. X
  994. /*
  995. X * Returns a pointer to a new FtpContext for which the connection is
  996. X * started. The external function RegisterFtpFd() is used to register
  997. X * the control socket for subsequent processing by ftpProcess().
  998. X */
  999. FtpContext *
  1000. ftpNewContext(hostname,user,pass,cwd,local_dir,type,stripcr,prompt,
  1001. X          filecmd,files,num_files,trace,done1,done)
  1002. char *hostname,*user,*pass,*cwd,*local_dir;
  1003. int type,stripcr,prompt,filecmd;
  1004. char **files;
  1005. int num_files;
  1006. FtpTraceProc trace;
  1007. FtpCallbackProc done1,done;
  1008. {
  1009. X    FtpContext *ftpc;
  1010. X    int i;
  1011. X
  1012. X    /* Initialize the data structure */
  1013. X    if ((ftpc=(FtpContext *)malloc(sizeof(FtpContext))) == NULL) {
  1014. X    fprintf(stderr,"ftpNewContext: malloc failed\n");
  1015. X    return(NULL);
  1016. X    }
  1017. X    /* User-specified stuff */
  1018. X    ftpc->hostname = NewString(hostname);
  1019. X    ftpc->user = NewString(user);
  1020. X    ftpc->pass = NewString(pass);
  1021. X    ftpc->cwd = NewString(cwd);
  1022. X    ftpc->wd = ftpc->cwd;
  1023. X    ftpc->local_dir = NewString(local_dir);
  1024. X    ftpc->type = type;
  1025. X    ftpc->stripcr = stripcr;
  1026. X    ftpc->prompt = prompt;
  1027. X    ftpc->filecmd = filecmd;
  1028. X    ftpc->num_files = num_files;
  1029. X    ftpc->files = (char **)calloc(num_files,sizeof(char *));
  1030. X    for (i=0; i < num_files; i++)
  1031. X    ftpc->files[i] = NewString(files[i]);
  1032. X    ftpc->this_file = -1;    /* preincrement later */
  1033. X    ftpc->this_size = 0;
  1034. X    ftpc->trace = trace;
  1035. X    ftpc->done1 = done1;
  1036. X    ftpc->done = done;
  1037. X    /* Default stuff */
  1038. X    ftpc->reply[0] = '\0';
  1039. X    ftpc->stripcr = 1;
  1040. X    /* Undefined stuff */
  1041. X    ftpc->ctrl = ftpc->data = ftpc->port = ftpc->local_fd = -1;
  1042. X    ftpc->state = ftpc->iostate = ftpc->reply_state = ftpc->saved_state = 0;
  1043. X    ftpc->retcode = ftpc->tmpcode = 0;
  1044. X    ftpc->cmd = NULL;
  1045. X    /* Go start the connection */
  1046. X    if (ftpGetHostAndPort(ftpc) < 0) {
  1047. X    ftpFreeContext(ftpc);
  1048. X    return(NULL);
  1049. X    }
  1050. X    ftpc->state = 0;
  1051. X    return(ftpc);
  1052. }
  1053. X
  1054. void
  1055. ftpFreeContext(ftpc)
  1056. FtpContext *ftpc;
  1057. {
  1058. X    int i;
  1059. X
  1060. X    DEBUG1("ftpFreeContext: ftpc=0x%x\n",ftpc);
  1061. X    if (ftpc->ctrl != -1) {
  1062. X    UnregisterFtpFd(ftpc,ftpc->ctrl);
  1063. X    DEBUG1("ftpFreeContext: closing ctrl %d\n",ftpc->ctrl);
  1064. X    close(ftpc->ctrl);
  1065. X    }
  1066. X    if (ftpc->data != -1) {
  1067. X    UnregisterFtpFd(ftpc,ftpc->data);
  1068. X    DEBUG1("ftpFreeContext: closing data %d\n",ftpc->data);
  1069. X    close(ftpc->data);
  1070. X    }
  1071. X    if (ftpc->port != -1) {
  1072. X    DEBUG1("ftpFreeContext: closing port %d\n",ftpc->port);
  1073. X    close(ftpc->port);
  1074. X    }
  1075. X    if (ftpc->local_fd != -1) {
  1076. X    DEBUG1("ftpFreeContext: closing local_fd %d\n",ftpc->local_fd);
  1077. X    close(ftpc->local_fd);
  1078. X    }
  1079. X    if (ftpc->hostname)
  1080. X    free(ftpc->hostname);
  1081. X    if (ftpc->user)
  1082. X    free(ftpc->user);
  1083. X    if (ftpc->pass)
  1084. X    free(ftpc->pass);
  1085. X    if (ftpc->cwd)
  1086. X    free(ftpc->cwd);
  1087. X    if (ftpc->local_dir)
  1088. X    free(ftpc->local_dir);
  1089. X    if (ftpc->files) {
  1090. X    for (i=0; i < ftpc->num_files; i++)
  1091. X        if (ftpc->files[i]) free(ftpc->files[i]);
  1092. X    free((char *)(ftpc->files));
  1093. X    }
  1094. X    if (ftpc->h_addr_list)
  1095. X    free((char *)(ftpc->h_addr_list));
  1096. X    DEBUG0("ftpFreeContext: done\n");
  1097. }
  1098. X
  1099. void
  1100. ftpStart(ftpc)
  1101. FtpContext *ftpc;
  1102. {
  1103. X    DEBUG1("ftpStart: ftpc=0x%x\n",ftpc);
  1104. X    ftpc->state = FTPS_OPEN;
  1105. X    ftpConnectCallback(ftpc);        /* get things started */
  1106. X    DEBUG0("ftpStart: done\n");
  1107. }
  1108. X
  1109. void
  1110. ftpAbort(ftpc)
  1111. FtpContext *ftpc;
  1112. {
  1113. X    DEBUG1("ftpAbort: ftpc=0x%x\n",ftpc);
  1114. X    /*
  1115. X     * If we're aborting before any files transferred or after an
  1116. X     * abort or quit, just close down the whole connection.
  1117. X     */
  1118. X    if (ftpc->state < FTPS_READY || ftpc->state > FTPS_EOF) {
  1119. X    ftpDone(ftpc);
  1120. X    return;
  1121. X    }
  1122. X    /*
  1123. X     * Close the dataconn so we don't get swamped in select() while
  1124. X     * waiting for the response to the abort on the ctrlconn.
  1125. X     */
  1126. X    if (ftpc->data != -1) {
  1127. X    UnregisterFtpFd(ftpc,ftpc->data);
  1128. X    }
  1129. X    /* Then send the abort sequence */
  1130. X    ftpSendAbort(ftpc);
  1131. X    DEBUG0("ftpAbort: done\n");
  1132. }
  1133. X
  1134. /*    -    -    -    -    -    -    -    -    */
  1135. /* Initialization: */
  1136. /*
  1137. X * This function is called from ftpNewContext() to initialize the host
  1138. X * address information in the FTPC.
  1139. X */
  1140. static int
  1141. ftpGetHostAndPort(ftpc)
  1142. FtpContext *ftpc;
  1143. {
  1144. X    struct servent *serv;
  1145. X    struct hostent *host;
  1146. X    unsigned long hostaddr;
  1147. X    char msg[256];
  1148. X    int i;
  1149. X
  1150. X    DEBUG2("ftpGetHostAndPort: ftpc=0x%x: \"%s\"\n",ftpc,ftpc->hostname);
  1151. X    /*
  1152. X     * Get ftp port
  1153. X     */
  1154. X    DEBUG0("ftpGetHostAndPort: getting ftp service port\n");
  1155. X    serv = getservbyname("ftp","tcp");
  1156. X    /* UCX needs 0 or -1 */
  1157. X    if (serv == (struct servent *)0 || serv == (struct servent *)-1) {
  1158. X    alert0("Can't find service 'ftp/tcp' in list of services -- using default port");
  1159. X    ftpc->servport = htons((unsigned short)IPPORT_FTP);
  1160. X    } else {
  1161. X    ftpc->servport = (unsigned short)serv->s_port;
  1162. X    }
  1163. X    DEBUG1("ftpGetHostAndPort: ftp service port is %d\n",ftpc->servport);
  1164. X    /*
  1165. X     * Get host address
  1166. X     */
  1167. X    sprintf(msg,"Getting address for host \"%.200s\"",ftpc->hostname);
  1168. X    status0(msg);
  1169. X    if ((host=gethostbyname(ftpc->hostname)) == NULL) {
  1170. X    DEBUG0("ftpGetHostAndPort: gethostbyname failed, trying inet_addr()\n");
  1171. X    /*
  1172. X     * If gethostbyname fails, then maybe we've been given an IP
  1173. X     * address directly. Let's see.
  1174. X     */
  1175. X    hostaddr = inet_addr(ftpc->hostname);
  1176. X    if (hostaddr == (unsigned long)-1) {
  1177. X        /*
  1178. X         * Nope - complete failure.
  1179. X         */
  1180. X        sprintf(msg,"Can't find address of host \"%.200s\"",
  1181. X            ftpc->hostname);
  1182. X        alert0(msg);
  1183. X        return(-1);
  1184. X    } else {
  1185. X        /*
  1186. X         * inet_addr succeeded, so we make a dummy array of hostaddrs.
  1187. X         */
  1188. X        ftpc->h_addr_list = (char **)calloc(2,sizeof(char *));
  1189. X        bcopy((char *)&hostaddr,ftpc->h_addr_list[0],sizeof(char *));
  1190. X        hostaddr = (unsigned long)0;
  1191. X        bcopy((char *)&hostaddr,ftpc->h_addr_list[1],sizeof(char *));
  1192. X        ftpc->this_addr = ftpc->h_addr_list-1; /* preincrement later */
  1193. X        DEBUG1("ftpGetHostAndPort: inet_addr returned %s\n",
  1194. X           inet_ntoa(*(struct in_addr*)(ftpc->h_addr_list[0])));
  1195. X        return(0);
  1196. X    }
  1197. X    } else {
  1198. X    /*
  1199. X     * If gethostbyname succeeeds, it fills in a list of addresses.
  1200. X     * We'll copy them into the ftpc.
  1201. X     */
  1202. X    for (i=0; host->h_addr_list[i]; i++)
  1203. X        /*EMPTY*/;
  1204. X    DEBUG1("ftpGetHostAndPort: gethostbynname returned %d addr(s)\n",i);
  1205. X    ftpc->h_addr_list = (char **)calloc(i+1,sizeof(char *));
  1206. X    for (i=0; host->h_addr_list[i]; i++) {
  1207. X        bcopy(host->h_addr_list[i],
  1208. X          (char *)(ftpc->h_addr_list+i),sizeof(char *));
  1209. X        DEBUG2("ftpGetHostAndPort: h_addr_list[%d] = %s\n",i,
  1210. X           inet_ntoa(*(struct in_addr*)(ftpc->h_addr_list+i)));
  1211. X    }
  1212. X    bzero((char *)(ftpc->h_addr_list+i),sizeof(char *));
  1213. X    ftpc->this_addr = ftpc->h_addr_list-1;    /* preincrement later */
  1214. X    return(0);
  1215. X    }
  1216. }
  1217. X
  1218. /*    -    -    -    -    -    -    -    -    */
  1219. /* Connection establishment: */
  1220. /*
  1221. X * This function goes through the list of addresses trying to connect to
  1222. X * the server. It is initially called from ftpNewContext(), and subsequently
  1223. X * whenever the ctrl socket it ready for writing (indicating connect()
  1224. X * completed, possibly with an error).
  1225. X */
  1226. static void
  1227. ftpConnectCallback(ftpc)
  1228. FtpContext *ftpc;
  1229. {
  1230. X    int retcode;
  1231. X    char msg[256];
  1232. X
  1233. X    DEBUG2("ftpConnectCallback: ftpc=0x%x, state=%s\n",
  1234. X       ftpc,ftpstatestr(ftpc->state));
  1235. X  redo:
  1236. X    switch (ftpc->state) {
  1237. X      case FTPS_OPEN:
  1238. X    ftpc->this_addr += 1;            /* preincrement */
  1239. X    DEBUG1("ftpConnectCallback: OPEN: %s\n",
  1240. X           inet_ntoa(*(struct in_addr*)(ftpc->this_addr)));
  1241. X    if (*(ftpc->this_addr)) {        /* Not at last host */
  1242. X        if (ftpGetSocket(ftpc) < 0) {
  1243. X        ftpDone(ftpc);
  1244. X        } else {
  1245. X        /* Arrange to get called back if connect() would block */
  1246. X        RegisterFtpFd(ftpc,ftpc->ctrl,O_RDWR,ftpConnectCallback);
  1247. X        ftpc->state = FTPS_CONNECT;
  1248. X        goto redo;
  1249. X        }
  1250. X    } else {                /* All hosts failed */
  1251. X        sprintf(msg,"Couldn't connect to host \"%s\"",ftpc->hostname);
  1252. X        alert0(msg);
  1253. X        ftpDone(ftpc);
  1254. X    }
  1255. X    break;
  1256. X      case FTPS_CONNECT:
  1257. X    /* We previously registered either above or below */
  1258. X    UnregisterFtpFd(ftpc,ftpc->ctrl);
  1259. X    retcode = ftpConnect(ftpc);
  1260. X    if (retcode < 0) {
  1261. X        DEBUG1("ftpConnectCallback: ftpConnect failed, closing ctrl %d\n",
  1262. X           ftpc->ctrl);
  1263. X        close(ftpc->ctrl);
  1264. X        ftpc->ctrl = -1;
  1265. X        ftpc->state = FTPS_OPEN;        /* try next one */
  1266. X        goto redo;
  1267. X    } else if (retcode == 0) {
  1268. X        DEBUG0("ftpConnectCallback: ftpConnect would block\n");
  1269. X        /* Arrange to get called back when connect() won't block */
  1270. X        RegisterFtpFd(ftpc,ftpc->ctrl,O_RDWR,ftpConnectCallback);
  1271. X        ftpc->state = FTPS_CONNECT;        /* try again when ready */
  1272. X    } else {
  1273. X        DEBUG0("ftpConnectCallback: ftpConnect ok\n");
  1274. X        ftpInitReply(ftpc);            /* ok... */
  1275. X        ftpc->state = FTPS_CONNECTED;    /* move on */
  1276. X    }
  1277. X    break;
  1278. X      default:
  1279. X    fprintf(stderr,"ftpConnectCallback: unknown state %d\n",ftpc->state);
  1280. X    abort();
  1281. X    }
  1282. X    DEBUG0("ftpConnectCallback: done\n");
  1283. }
  1284. X        
  1285. /*    -    -    -    -    -    -    -    -    */
  1286. /* Functions called by ftpConnectCallback(): */
  1287. /*
  1288. X * This function opens a new socket for the ctrl connection, and sets
  1289. X * it up for non-blocking IO. Everything is setup for later connect().
  1290. X */
  1291. static int
  1292. ftpGetSocket(ftpc)
  1293. FtpContext *ftpc;
  1294. {
  1295. X    DEBUG1("ftpGetSocket: addr=%s\n",
  1296. X       inet_ntoa(*(struct in_addr*)(ftpc->this_addr)));
  1297. X    /* Get a socket */
  1298. X    if ((ftpc->ctrl=socket(AF_INET,SOCK_STREAM,0)) < 0) {
  1299. X    sysError("socket(ftpGetSocket)");
  1300. X    return(-1);
  1301. X    }
  1302. X    DEBUG1("ftpGetSocket: socket() returned %d\n",ftpc->ctrl);
  1303. X    /*
  1304. X     * According to jbh@moses.aii.COM, we can't do this until we connect
  1305. X     * on (at least) ISC variants of SYS5. I have not had problems with
  1306. X     * other SYS5 systems, including HPUX. When ISC is defined, we do it
  1307. X     * in ftpConnect(), although we may then block in connect().
  1308. X     */
  1309. #ifndef ISC
  1310. X    /* Setup socket for async i/o */
  1311. X    MAKE_NONBLOCKING(ftpc->ctrl);
  1312. #endif
  1313. X    /* Set up the address spec. */
  1314. X    bzero((char *)&(ftpc->saddr),sizeof(struct sockaddr_in));
  1315. X    ftpc->saddr.sin_family = AF_INET;
  1316. X    ftpc->saddr.sin_port = ftpc->servport;
  1317. X    ftpc->saddr.sin_addr = *((struct in_addr *)(ftpc->this_addr));
  1318. X    /* Ready to connect() */
  1319. X    DEBUG0("ftpGetSocket: done\n");
  1320. X    return(0);
  1321. }
  1322. X
  1323. /*
  1324. X * Calls connect(). Returns -1 if this host is botched, 0 if connect()
  1325. X * would have blocked, or 1 if we should proceed. 
  1326. X */
  1327. static int
  1328. ftpConnect(ftpc)
  1329. FtpContext *ftpc;
  1330. {
  1331. X    int retcode,addrlen;
  1332. X    char msg[256];
  1333. X
  1334. X    sprintf(msg,"Connecting to %.200s (%s)",
  1335. X        ftpc->hostname,inet_ntoa(*(struct in_addr*)(ftpc->this_addr)));
  1336. X    status0(msg);
  1337. X    DEBUG0("ftpConnect: calling connect()...\n");
  1338. X    retcode = connect(ftpc->ctrl,(struct sockaddr *)&(ftpc->saddr),
  1339. X              sizeof(struct sockaddr_in));
  1340. X    if (retcode < 0 && errno == EINPROGRESS) {
  1341. X    DEBUG0("ftpConnect: connect() EINPROGRESS\n");
  1342. X    return(0);
  1343. X    } else if (retcode < 0 && errno != EISCONN) {
  1344. #ifdef DEBUG
  1345. X    perror("ftpConnect: connect()");
  1346. #endif
  1347. X    return(-1);
  1348. X    }
  1349. #ifdef DEBUG
  1350. X      else if (retcode < 0 && errno == EISCONN)
  1351. X      fprintf(stderr,"ftpConnect: connect() EISCONN\n");
  1352. X      else
  1353. X      fprintf(stderr,"ftpConnect: connect() returned ok\n");
  1354. #endif
  1355. X     /* According to jbh@moses.aii.COM, see comments in ftpGetSocket(). */
  1356. #ifdef ISC
  1357. X    MAKE_NONBLOCKING(ftpc->ctrl); /* Setup socket for async i/o */
  1358. #endif
  1359. X    /* Get name (address) of socket */
  1360. X    addrlen = sizeof(struct sockaddr_in);
  1361. X    retcode =
  1362. X    getsockname(ftpc->ctrl,(struct sockaddr *)&(ftpc->saddr),&addrlen);
  1363. X    if (retcode < 0) {
  1364. X    sysError("getsockname(ftpConnect)");
  1365. X    return(-1);
  1366. X    }
  1367. X    DEBUG1("ftpConnect: getsockname() returned %s\n",
  1368. X       inet_ntoa(ftpc->saddr.sin_addr));
  1369. X    return(1);
  1370. }
  1371. X
  1372. /*    -    -    -    -    -    -    -    -    */
  1373. /* Reading server replies: */
  1374. /*
  1375. X * This function must be called to initialize the reply in the FTPC and
  1376. X * to ensure that the appropriate callback is registered to read it.
  1377. X */
  1378. static void
  1379. ftpInitReply(ftpc)
  1380. FtpContext *ftpc;
  1381. {
  1382. X    DEBUG1("ftpInitReply: ftpc=0x%lx\n",ftpc);
  1383. X    ftpc->retcode = 0;
  1384. X    ftpc->reply_len = 0;
  1385. X    *(ftpc->reply) = '\0';
  1386. X    ftpc->reply_state = FTPS_REPLY_CODE;
  1387. X    /* We're expecting a reply, so register ctrl for reading only */
  1388. X    RegisterFtpFd(ftpc,ftpc->ctrl,O_RDONLY,ftpReplyCallback);
  1389. X    DEBUG0("ftpInitReply: done\n");
  1390. }
  1391. X
  1392. /*
  1393. X * This function is the low-level reply parser. It reads and
  1394. X * parses reply messages from the server, handles TELNET commands,
  1395. X * and translate codes in the reply prefix into integers. It stores the
  1396. X * reply code in ftpc->retcode and puts the text of the reply in ftpc->reply.
  1397. X * It is called whenever the ctrlconn is ready for reading and we are
  1398. X * expecting a reply (ie., after ftpInitReply()). Once the reply is
  1399. X * complete, we call ftpProcessReply().
  1400. X */
  1401. static void
  1402. ftpReplyCallback(ftpc)
  1403. FtpContext *ftpc;
  1404. {
  1405. X    int n;
  1406. X    unsigned char c,cc;
  1407. X
  1408. X    for (;;) {
  1409. /*
  1410. X    DEBUG2("ftpReplyCallback: ftpc=0x%x, reply_state=%s\n",
  1411. X           ftpc,ftpstatestr(ftpc->reply_state));
  1412. */
  1413. X    n = read(ftpc->ctrl,&c,1);        /* Read a byte */
  1414. X    if (n < 0 && errno != ITWOULDBLOCK) {        /* Error */
  1415. X        sysError("read(ftpReplyCallback)");
  1416. X        DEBUG0("ftpReplyCallback: error reading ctrlconn\n");
  1417. X        ftpDone(ftpc);
  1418. X        return;
  1419. X    } else if (n < 0 && errno == ITWOULDBLOCK) {    /* Would block */
  1420. X        /*DEBUG0("ftpReplyCallback: ctrlconn would block\n");*/
  1421. X        return;
  1422. X    } else if (n == 0) {            /* EOF */
  1423. X        *(ftpc->reply+ftpc->reply_len) = '\0';
  1424. X        /* Could check against current retcode, if any... */
  1425. X        if (ftpc->state == FTPS_QUIT)
  1426. X        ftpc->retcode = FTP_SERVICE_CLOSING;
  1427. X        else
  1428. X        ftpc->retcode = FTP_SERVICE_UNAVAILABLE;
  1429. X        DEBUG1("ftpReplyCallback: EOF: retcode = %d\n",ftpc->retcode);
  1430. X        /* Reply is done, go process it */
  1431. X        break;
  1432. X    }
  1433. X    /*
  1434. X     * Otherwise, we got something, process it.
  1435. X     */
  1436. X    if (c == IAC) {            /* Telnet IAC */
  1437. X        ftpc->saved_state = ftpc->reply_state;
  1438. X        ftpc->reply_state = FTPS_REPLY_IAC1;
  1439. X        DEBUG1("ftpReplyCallback: IAC (saved_state=%d)\n",ftpc->saved_state);
  1440. X        continue;
  1441. X    } else if (c == '\r') {        /* Skip <CR>, is this ok? */
  1442. X        continue;
  1443. X    }
  1444. X    /*
  1445. X     * We got something that's not IAC, process it.
  1446. X     */
  1447. X    /*DEBUG2("ftpReplyCallback: `%c' (%d)\n",c,c);*/
  1448. X    switch (ftpc->reply_state) {
  1449. X      case FTPS_REPLY_IAC1:
  1450. X        DEBUG1("ftpReplyCallback: IAC %c",c);
  1451. X        ftpc->reply_state = FTPS_REPLY_IAC2;
  1452. X        break;
  1453. X      case FTPS_REPLY_IAC2:
  1454. X        switch (c) {
  1455. X          case WILL:
  1456. X          case WONT: c = DONT;
  1457. X             break;
  1458. X          case DO:
  1459. X          case DONT: c = WONT;
  1460. X             break;
  1461. X          default:
  1462. X        DEBUG0(" (ignored)\n");
  1463. X        continue;
  1464. X        }
  1465. X        DEBUG1(", reply %c\n",c);
  1466. X        cc = IAC;
  1467. X        write(ftpc->ctrl,&cc,1);
  1468. X        write(ftpc->ctrl,&c,1);
  1469. X        ftpc->reply_state = FTPS_REPLY_IAC3;
  1470. X        break;
  1471. X      case FTPS_REPLY_IAC3:
  1472. X        write(ftpc->ctrl,&c,1);
  1473. X        ftpc->reply_state = ftpc->saved_state;
  1474. X        DEBUG1("ftpReplyCallback: IAC done, restored state = %d\n",
  1475. X           ftpc->reply_state);
  1476. X        break;
  1477. X      case FTPS_REPLY_CODE:
  1478. X        if (c < '0' || c > '9') {
  1479. X        *(ftpc->reply+ftpc->reply_len) = '\0';
  1480. X        DEBUG1("ftpReplyCallback: CODE: retcode = %d\n",ftpc->retcode);
  1481. X        goto done;
  1482. X        }
  1483. X        *(ftpc->reply+ftpc->reply_len++) = c;
  1484. X        ftpc->retcode = ftpc->retcode * 10 + c - '0';
  1485. X        /*DEBUG1("ftpReplyCallback: retcode now %d\n",ftpc->retcode);*/
  1486. X        if (ftpc->retcode >= 100)
  1487. X        ftpc->reply_state = FTPS_REPLY_CONT;
  1488. X        break;
  1489. X      case FTPS_REPLY_CONT:
  1490. X        /* we reach here after we finished reading the code or when we
  1491. X         * struck a line beginning with at least three digits, check if
  1492. X         * this is the last line of the reply
  1493. X         */
  1494. X        *(ftpc->reply+ftpc->reply_len++) = c;
  1495. X        if (c == '-') {
  1496. /*
  1497. X        DEBUG0("ftpReplyCallback: continuation\n");
  1498. */
  1499. X        ftpc->reply_state = FTPS_REPLY_MORE;
  1500. X        } else {
  1501. /*
  1502. X        DEBUG0("ftpReplyCallback: final line\n");
  1503. */
  1504. X        ftpc->reply_state = FTPS_REPLY_LAST;
  1505. X        }
  1506. X        break;
  1507. X      case FTPS_REPLY_LAST:
  1508. X        if (c == '\n') {
  1509. X        *(ftpc->reply+ftpc->reply_len) = '\0';
  1510. /*
  1511. X        DEBUG1("ftpReplyCallback: LAST: retcode = %d\n",ftpc->retcode);
  1512. */
  1513. X        goto done;
  1514. X        } else {
  1515. X        *(ftpc->reply+ftpc->reply_len++) = c;
  1516. /*
  1517. X        DEBUG3("ftpReplyCallback: LAST: %03d: \"%.*s\"\n",
  1518. X             ftpc->reply_len,ftpc->reply_len,ftpc->reply);
  1519. */
  1520. X        }
  1521. X        break;
  1522. X      case FTPS_REPLY_MORE:
  1523. X        *(ftpc->reply+ftpc->reply_len++) = c;
  1524. /*
  1525. X        DEBUG3("ftpReplyCallback: MORE: %03d: \"%.*s\"\n",
  1526. X           ftpc->reply_len,ftpc->reply_len,ftpc->reply);
  1527. */
  1528. X        if (c == '\n') {
  1529. X        ftpc->tmpcode = 0;
  1530. X        ftpc->reply_state = FTPS_REPLY_CHCK;
  1531. X        }
  1532. X        break;
  1533. X      case FTPS_REPLY_CHCK:
  1534. X        if (c < '0' || c > '9') {
  1535. X        *(ftpc->reply+ftpc->reply_len++) = c;
  1536. /*
  1537. X        DEBUG3("ftpReplyCallback: CHCK: %03d: \"%.*s\"\n",
  1538. X               ftpc->reply_len,ftpc->reply_len,ftpc->reply);
  1539. */
  1540. X        ftpc->reply_state = FTPS_REPLY_MORE;
  1541. X        } else {
  1542. X        ftpc->tmpcode = ftpc->tmpcode * 10 + c - '0';
  1543. X        if (ftpc->tmpcode >= 100) {
  1544. X            if (ftpc->tmpcode != ftpc->retcode)
  1545. X            ftpc->reply_state = FTPS_REPLY_MORE;
  1546. X            else
  1547. X            ftpc->reply_state = FTPS_REPLY_CONT;
  1548. X        }
  1549. X        }
  1550. X        break;
  1551. X      default:
  1552. X        fprintf(stderr,"ftpReplyCallback: unknown reply_state %d\n",
  1553. X            ftpc->reply_state);
  1554. X        abort();
  1555. X    }
  1556. X    }
  1557. X    /* if we get here, the reply is complete */
  1558. X  done:
  1559. X    UnregisterFtpFd(ftpc,ftpc->ctrl);
  1560. X    if (ftpc->trace) {
  1561. X    (*(ftpc->trace))(ftpc,0,ftpc->reply);
  1562. X    }
  1563. X    ftpProcessReply(ftpc);
  1564. }
  1565. X
  1566. /*    -    -    -    -    -    -    -    -    */
  1567. /*
  1568. X * This function implements the high-level FTP protocol using the state
  1569. X * field of the FTPC. It is called from ftpReplyCallback() once we've read
  1570. X * a reply and need to process it.
  1571. X */
  1572. static void
  1573. ftpProcessReply(ftpc)
  1574. FtpContext *ftpc;
  1575. {
  1576. X    char cmd[256];
  1577. X
  1578. X    DEBUG3("ftpProcessReply: ftpc=0x%x, state=%s, retcode=%d\n",
  1579. X       ftpc,ftpstatestr(ftpc->state),ftpc->retcode);
  1580. X  redo:
  1581. X    switch (ftpc->state) {
  1582. X      case FTPS_CONNECTED:
  1583. X    if (ftpc->retcode == FTP_SERVICE_RDY_TIME) {    /* delay NNN minutes */
  1584. X        DEBUG0("ftpProcessReply: server not ready\n");
  1585. X        ftpAlert(ftpc);
  1586. X    } else if (ftpc->retcode == FTP_SERVICE_RDY_USER) {/* ready for USER */
  1587. X        sprintf(cmd,"USER %s",ftpc->user);
  1588. X        status0(cmd);
  1589. X        ftpc->state = FTPS_USER;
  1590. X        ftpSendCmd(ftpc,cmd);
  1591. X    } else {                /* FTP_SERVICE_UNAVAILABLE */
  1592. X        ftpAlert(ftpc);
  1593. X        ftpDone(ftpc);
  1594. X    }
  1595. X    break;
  1596. X      case FTPS_USER:
  1597. X    if (ftpc->retcode == FTP_LOGIN_OK) {    /* USER ok, no PASS needed */
  1598. X        ftpc->retcode = FTP_FILE_ACTION_OK;
  1599. X        ftpc->state = FTPS_CWD;
  1600. X        goto redo;
  1601. X    } else if (ftpc->retcode == FTP_LOGIN_NEED_PASSWD) {    /* USER ok   */
  1602. X        sprintf(cmd,"PASS %s",ftpc->pass);            /* need PASS */
  1603. X        status0(cmd);
  1604. X        ftpc->state = FTPS_PASS;
  1605. X        ftpSendCmd(ftpc,cmd);
  1606. X    } else {                /* ACCT needed or error */
  1607. X        ftpHandleErrorThenQuit(ftpc);
  1608. X    }
  1609. X    break;
  1610. X      case FTPS_PASS:
  1611. X    if (ftpc->retcode == FTP_LOGIN_OK) {    /* PASS ok, ready to go */
  1612. X        ftpc->retcode = FTP_FILE_ACTION_OK;
  1613. X        ftpc->state = FTPS_CWD;
  1614. X        goto redo;
  1615. X    } else {                /* ACCT needed or error */
  1616. X        ftpHandleErrorThenQuit(ftpc);
  1617. X    }
  1618. X    break;
  1619. X      case FTPS_CWD:
  1620. X    /* can come here direct from USER or PASS also... */
  1621. X    if (ftpc->retcode == FTP_FILE_ACTION_OK) {    /* last CWD ok */
  1622. X        if (ftpc->wd == NULL || *(ftpc->wd) == '\0') { /* CWD done */
  1623. X        ftpc->state = FTPS_TYPE;
  1624. X        ftpSendType(ftpc);
  1625. X        } else {                /* send next part of CWD */
  1626. X        ftpc->state = FTPS_CWD;
  1627. X        ftpSendNextCwd(ftpc);
  1628. X        }
  1629. X    } else {                /* last CWD failed */
  1630. X        ftpHandleErrorThenQuit(ftpc);
  1631. X    }
  1632. X    break;
  1633. X      case FTPS_TYPE:
  1634. X    if (ftpc->retcode == FTP_COMMAND_OK) {    /* TYPE ok */
  1635. X        ftpc->retcode = FTP_FILE_ACTION_OK;
  1636. X        ftpc->state = FTPS_READY;
  1637. X        goto redo;
  1638. X    } else {                /* TYPE failed */
  1639. X        ftpHandleErrorThenQuit(ftpc);
  1640. X    }
  1641. X    break;
  1642. X      case FTPS_READY:
  1643. X    /* can get here from TYPE or EOF */
  1644. X    ftpc->this_file += 1;
  1645. X    if (ftpc->this_file < ftpc->num_files) {  /* files left to transfer */
  1646. X        sprintf(cmd,"File %s?",ftpc->files[ftpc->this_file]);
  1647. X        status0(cmd);
  1648. X        if (ftpc->prompt && !ftpPrompt(ftpc)) {
  1649. X        goto redo;
  1650. X        }
  1651. X        if (ftpSendPort(ftpc) == 0) {    /*   PORT ok locally */
  1652. X        ftpc->state = FTPS_PORT;
  1653. X        } else {                /*   PORT failed locally */
  1654. X        ftpc->state = FTPS_QUIT;    /*     bag the whole thing */
  1655. X        ftpSendCmd(ftpc,"QUIT");
  1656. X        }
  1657. X    } else {                /* no files left to transfer */
  1658. X        DEBUG0("ftpProcessReply: no more files\n");
  1659. X        ftpc->state = FTPS_QUIT;
  1660. X        ftpSendCmd(ftpc,"QUIT");
  1661. X    }
  1662. X    break;
  1663. X      case FTPS_PORT:
  1664. X    if (ftpc->retcode == FTP_COMMAND_OK) {    /* PORT command ok */
  1665. X        ftpc->state = FTPS_GETPUT;
  1666. X        ftpSendGetPut(ftpc);
  1667. X    } else {                /* PORT failed */
  1668. X        if (ftpc->port >= 0) {
  1669. X        DEBUG1("ftpProcessReply: closing port %d\n",ftpc->port);
  1670. X        close(ftpc->port);
  1671. X        ftpc->port = -1;
  1672. X        }
  1673. X        ftpHandleErrorThenQuit(ftpc);
  1674. X    }
  1675. X    break;
  1676. X      case FTPS_GETPUT:
  1677. X    if (FTP_REPLY_PRELIM(ftpc->retcode)) { /* dataconn ready */
  1678. X        status0(ftpc->reply+4);
  1679. X        if (sscanf(ftpc->reply,"%*[^(](%d bytes)",&(ftpc->this_size)) != 1)
  1680. X        ftpc->this_size = 0;
  1681. X        if (ftpAcceptDataConn(ftpc) < 0) {        /*  local failure */
  1682. X        if (ftpc->port != -1) {            /*    give up */
  1683. X            DEBUG1("ftpProcessReply: closing port %d\n",ftpc->port);
  1684. X            close(ftpc->port);
  1685. X            ftpc->port = -1;
  1686. X        }
  1687. X        ftpc->state = FTPS_QUIT;
  1688. X        ftpSendCmd(ftpc,"QUIT");
  1689. X        } else if (ftpSetupLocalData(ftpc) < 0) {    /*  local failure */
  1690. X        UnregisterFtpFd(ftpc,ftpc->data);    /*    don't give up */
  1691. X        if (ftpc->data != -1) {
  1692. X            DEBUG1("ftpProcessReply: closing data %d\n",ftpc->data);
  1693. X            close(ftpc->data);
  1694. X            ftpc->data = -1;
  1695. X        }
  1696. X        ftpc->state = FTPS_READY;        /*    do next file */
  1697. X        goto redo;
  1698. X        } else {                /* all ok locally */
  1699. X        ftpc->state = FTPS_TRANSFER;
  1700. X        }
  1701. X    } else if (ftpc->retcode == FTP_FILE_UNAVAILABLE ||    /* datacon */
  1702. X           ftpc->retcode == FTP_ACTION_NOT_TAKEN) {    /* failed  */
  1703. X        if (ftpc->port != -1) {                /*  minor  */
  1704. X        DEBUG1("ftpProcessReply: closing port %d\n",ftpc->port);
  1705. X        close(ftpc->port);                /*  error */
  1706. X        ftpc->port = -1;
  1707. X        }
  1708. X        ftpAlert(ftpc);                /* error msg */
  1709. X        ftpc->state = FTPS_READY;        /* next file */
  1710. X        goto redo;
  1711. X    } else {
  1712. X        ftpHandleErrorThenQuit(ftpc);    /* real error */
  1713. X    }
  1714. X    break;
  1715. X      case FTPS_TRANSFER:
  1716. X    /* Shouldn't get here since dataconn is separately managed */
  1717. X    DEBUG0("ftpProcessReply: called in state TRANSFER!\n");
  1718. X    break;
  1719. X      case FTPS_EOF:
  1720. X    /* Called when the dataconn is closed, for whatever reason */
  1721. X    if (!FTP_REPLY_OK(ftpc->retcode)) {    /* dataconn closed error */
  1722. X        ftpAlert(ftpc);
  1723. X    }
  1724. X    ftpc->state = FTPS_READY;
  1725. X    goto redo;
  1726. X      case FTPS_QUIT:
  1727. X    if (ftpc->retcode != FTP_SERVICE_CLOSING) {    /* error */
  1728. X        ftpAlert(ftpc);
  1729. X    }
  1730. X    ftpDone(ftpc);                /* close, deallocate */
  1731. X    break;
  1732. X      case FTPS_ABORT:
  1733. X    if (ftpc->retcode == 552) {        /* NIC-style abort */
  1734. X        ftpc->state = FTPS_ABORT;        /* get another reply */
  1735. X    } else {
  1736. X        if (ftpc->retcode != FTP_DATA_CLOSE_ABORT) { /* 426      */
  1737. X        ftpAlert(ftpc);                 /* expected */
  1738. X        }
  1739. X        ftpc->state = FTPS_ABORT2;        /* get real reply */
  1740. X        ftpInitReply(ftpc);
  1741. X    }
  1742. X    break;
  1743. X      case FTPS_ABORT2:
  1744. X    if (!FTP_REPLY_OK(ftpc->retcode)) {    /* abort error */
  1745. X        ftpAlert(ftpc);
  1746. X    }
  1747. X    ftpCleanupDataConn(ftpc);
  1748. X    ftpc->state = FTPS_READY;
  1749. X    goto redo;
  1750. X      default:
  1751. X    fprintf(stderr,"ftpProcessReply: unknown state: %d\n",ftpc->state);
  1752. X    abort();
  1753. X    }
  1754. X    DEBUG0("ftpProcessReply: done\n");
  1755. }
  1756. X
  1757. /*
  1758. X * This function just puts up an FTP error message.
  1759. X */
  1760. static void
  1761. ftpAlert(ftpc)
  1762. FtpContext *ftpc;
  1763. {
  1764. X    char buf[256],*msg;
  1765. X    int len;
  1766. X
  1767. X    msg = ftpc->reply+4;        /* skip code */
  1768. X    len = strlen(msg);
  1769. X    if (len < 230) {
  1770. X    sprintf(buf,"FTP Error %d:\n %s",ftpc->retcode,msg);
  1771. X    } else {
  1772. X    sprintf(buf,"FTP Error %d: ...\n %.230s",ftpc->retcode,msg+len-230);
  1773. X    }
  1774. X    alert0(buf);
  1775. }
  1776. X
  1777. /*
  1778. X * This prints an error message, then sends the QUIT command (or
  1779. X * calls ftpDone() if the server shut down).
  1780. X */
  1781. static void
  1782. ftpHandleErrorThenQuit(ftpc)
  1783. FtpContext *ftpc;
  1784. {
  1785. X    ftpAlert(ftpc);
  1786. X    /* Don't bother with QUIT if remote host closing down */
  1787. X    if (ftpc->retcode == FTP_SERVICE_UNAVAILABLE) {
  1788. X    ftpDone(ftpc);
  1789. X    } else {
  1790. X    status0("Quitting...");
  1791. X    ftpc->state = FTPS_QUIT;
  1792. X    ftpSendCmd(ftpc,"QUIT");
  1793. X    }
  1794. }
  1795. X
  1796. /*
  1797. X * This calls the done function (or ftpFreeContext() if none is defined
  1798. X * for FTPC. All connections should pass through here to be cleaned up
  1799. X * regardless of how they got here.
  1800. X */
  1801. static void
  1802. ftpDone(ftpc)
  1803. FtpContext *ftpc;
  1804. {
  1805. X    DEBUG1("ftpDone: ftpc=0x%x\n",ftpc);
  1806. X    if (ftpc->done != NULL) {
  1807. X    (*(ftpc->done))(ftpc);
  1808. X    } else {
  1809. X    ftpFreeContext(ftpc);
  1810. X    }
  1811. X    DEBUG0("ftpDone: done\n");
  1812. SHAR_EOF
  1813. true || echo 'restore of xarchie-2.0.6/ftp.c failed'
  1814. fi
  1815. echo 'End of xarchie-2.0.6 part 8'
  1816. echo 'File xarchie-2.0.6/ftp.c is continued in part 9'
  1817. echo 9 > _shar_seq_.tmp
  1818. exit 0
  1819.  
  1820. exit 0 # Just in case...
  1821. -- 
  1822.   // chris@IMD.Sterling.COM       | Send comp.sources.x submissions to:
  1823. \X/  Amiga - The only way to fly! |    sources-x@imd.sterling.com
  1824.  "It's intuitively obvious to the |
  1825.   most casual observer..."        | GCS d+/-- p+ c++ l+ m+ s++/+ g+ w+ t+ r+ x+
  1826.