home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / x / volume19 / xgetftp / part02 < prev    next >
Encoding:
Text File  |  1993-04-27  |  39.5 KB  |  1,725 lines

  1. Newsgroups: comp.sources.x
  2. From: salim@tigger.cs.colorado.edu (Salim Alam)
  3. Subject: v19i023:  xgetftp - Friendly anonymous ftp tool, Part02/04
  4. Message-ID: <1993Mar10.164824.21368@sparky.imd.sterling.com>
  5. X-Md4-Signature: 0f18b40b60975db2b05e23a6e8df909b
  6. Date: Wed, 10 Mar 1993 16:48:24 GMT
  7. Approved: chris@sparky.imd.sterling.com
  8.  
  9. Submitted-by: salim@tigger.cs.colorado.edu (Salim Alam)
  10. Posting-number: Volume 19, Issue 23
  11. Archive-name: xgetftp/part02
  12. Environment: X11, OSF/Motif
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 2 (of 4)."
  21. # Contents:  control.c control.h file_cache.c file_cache.h ftp.c ftp.h
  22. # Wrapped by salim@anchor on Mon Mar  8 14:05:48 1993
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'control.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'control.c'\"
  26. else
  27. echo shar: Extracting \"'control.c'\" \(19375 characters\)
  28. sed "s/^X//" >'control.c' <<'END_OF_FILE'
  29. X/**************************************************************************
  30. X * MODULE:
  31. X *  control
  32. X *
  33. X * DESCRIPTION:
  34. X *  Provides a high-level interface to the ftp and cache modules.
  35. X *  Basically, this is the module that will provide all the functionality
  36. X *  to the user-interface.
  37. X *
  38. X * AUTHOR:
  39. X *  Salim Alam
  40. X *  University of Colorado, Boulder
  41. X * 
  42. X * MODIFICATION LOG:
  43. X *  93.02.15 S.A. - ctrl_delete_cache now reloads directory info from the
  44. X *                  server.  also slightly rewrote ctrl_start_session to
  45. X *            allow code reuse.
  46. X *  93.02.03 S.A. - Better error handling: ctrl_start_session, ctrl_down_dir
  47. X *            and read_directory.
  48. X *  92.12.29 S.A. - Better handling of login.  Added ctrl_delete_file_cache.
  49. X *            Better handling of "response_stream" -- allows main prog.
  50. X *            to arbirarily specify where most responses go.
  51. X *  92.12.16 S.A. - Fixed file view bug.  Better cleanup of /tmp.
  52. X *            Added ctrl_delete_cache function.
  53. X *  92.12.11 S.A. - Added function to query name of item in cache.  
  54. X *            Now also check user prefs to see how much caching
  55. X *            should be done.
  56. X *  92.12.09 S.A. - Using "/tmp" for temporary files now :)  Added dir
  57. X *            caching support.
  58. X *  92.12.01 S.A. - Added directory retrieval and new file view routine.  
  59. X *  92.11.24 S.A. - Added mods to handle X-based I/O.
  60. X *  92.10.27 S.A. - Changed use of InitFunc & CreateFunc. Added function
  61. X *            ftp_set_type.  Also now use the type field in struct
  62. X *            fileinfo to check for correctness of commands.
  63. X *
  64. X **************************************************************************/
  65. X
  66. X#include <X11/Xos.h>
  67. X#include <stdio.h>
  68. X#include <sys/stat.h>
  69. X#include <malloc.h>
  70. X#include "ftp.h"
  71. X#include "cache.h"
  72. X#include "file_cache.h"
  73. X#include "control.h"
  74. X#include "prefs.h"
  75. X
  76. X#ifndef TRUE
  77. X#define TRUE 1
  78. X#define FALSE 0
  79. X#endif
  80. X
  81. X#define XGETFTP
  82. X#ifdef XGETFTP
  83. X#define INBUFSIZE 1024
  84. X#include <X11/Intrinsic.h>
  85. Xextern XtAppContext app_context;
  86. X#endif
  87. X
  88. X
  89. X/*
  90. X * exported variables
  91. X */
  92. Xint ftp_curr_type = -1;
  93. Xint x_data_done = 1;
  94. X
  95. X
  96. X/*
  97. X * global vars
  98. X */
  99. Xstatic InitFunc   F_init_str;
  100. Xstatic CreateFunc F_add_str;
  101. X
  102. X
  103. X
  104. X/*
  105. X * useful internal functions
  106. X */
  107. Xint read_directory(char *path, cacheinfo_ptr *plevel, cacheinfo_ptr prev);
  108. Xvoid x_get_data(FILE *, int *, XtInputId *);
  109. Xchar *server_get_root(void);
  110. X
  111. X
  112. X/********************** login/logout functions ***************************/
  113. X
  114. Xint ctrl_login(char *host, char *user, char *pass)
  115. X/*
  116. X * Connect to the server whose name is "host" and log in.  If
  117. X * user and pass are specified, they will be used to log into a
  118. X * user account, else the user "anonymous" will be used.
  119. X *
  120. X * Success returns TRUE, failure returns FALSE.  
  121. X * Fatal errors may occur, in which case there is no return.
  122. X */
  123. X{
  124. X    /*
  125. X     * Connect to the server.
  126. X     */
  127. X    if (!ftp_init_conn(host))
  128. X    {
  129. X    fprintf(stderr, "ctrl_login: cannot connect to '%s'\n", host);
  130. X    return FALSE;
  131. X    }
  132. X
  133. X    if (ftp_get_response(response_stream) >= 300)
  134. X    {
  135. X    fprintf(stderr, "ctrl_login: cannot connect to '%s'\n", host);
  136. X    return FALSE;
  137. X    }
  138. X
  139. X    /*
  140. X     * Try to log in
  141. X     */
  142. X    if (!user)
  143. X    {
  144. X    user = "anonymous";
  145. X    pass = "guest";
  146. X    }
  147. X
  148. X    if (ftp_send_command("USER %s", user) >= 400)
  149. X    {
  150. X    fprintf(stderr, "ctrl_login: cannot login as '%s'\n", user);
  151. X    return FALSE;
  152. X    }
  153. X
  154. X    if (ftp_send_command("PASS %s", pass) >= 400)
  155. X    {
  156. X    fprintf(stderr, "ctrl_login: invalid password\n");
  157. X    return FALSE;
  158. X    }
  159. X
  160. X
  161. X    /*
  162. X     * Initialize File Cache
  163. X     */
  164. X    fc_set_root_dir(host);
  165. X
  166. X    return TRUE;
  167. X}
  168. X
  169. X
  170. X
  171. Xvoid ctrl_logout(void)
  172. X{
  173. X    ftp_close_conn();
  174. X    ftp_curr_type = -1;
  175. X    x_data_done = 1;
  176. X    cache_free_levels(&toplevel);
  177. X}
  178. X
  179. X
  180. Xint ctrl_start_session(InitFunc init_str, CreateFunc add_str)
  181. X{
  182. X    char *s;
  183. X    int i;
  184. X
  185. X    /*
  186. X     * save values for init_str and add_str
  187. X     */
  188. X    F_init_str = init_str;
  189. X    F_add_str  = add_str;
  190. X
  191. X    /* set type to IMAGE */
  192. X    ctrl_set_type(typIMAGE);
  193. X
  194. X    /*
  195. X     * If we're using previous directory cache, load it
  196. X     */
  197. X    cache_set_root("");
  198. X    if (user_prefs.reuse_dir && ctrl_load_cache())
  199. X    {
  200. X#ifdef DEBUG
  201. X    fprintf(stderr, "Reusing directory cache.\n");
  202. X#endif
  203. X    goto done;
  204. X    }
  205. X
  206. X
  207. X    /*
  208. X     * Otherwise, query server for info....
  209. X     */
  210. X    if ( (s=server_get_root()) == NULL )
  211. X    return FALSE;
  212. X
  213. X    cache_set_root(s);
  214. X
  215. X
  216. X    /*
  217. X     * get listing of root dir
  218. X     */
  219. X    if (!read_directory(s, &toplevel, NULL))
  220. X    {
  221. X    fprintf(stderr, "ctrl_start_session: can't read root dir!\n");
  222. X    return FALSE;
  223. X    }
  224. X
  225. Xdone:
  226. X    currlevel = toplevel;
  227. X
  228. X    /*
  229. X     * create outgoing data using add_str
  230. X     */
  231. X    init_str(toplevel->num_entries);
  232. X
  233. X    for (i=0; i < toplevel->num_entries; i++)
  234. X    {
  235. X    add_str(toplevel->entry_arr[i].line);
  236. X    }
  237. X
  238. X    return TRUE;
  239. X}
  240. X
  241. X
  242. X/********************** directory movement *******************************/
  243. X
  244. Xint ctrl_down_dir(int index)
  245. X/*
  246. X * This function attempts to traverse the directory tree at the entry
  247. X * specified by "index".  If that directory has been cached, it will
  248. X * use the cached version, otherwise it will bring in the contents of
  249. X * the directory remotely and cache it.  F_init_str is called once,
  250. X * and then F_add_str is called for each entry.
  251. X *
  252. X * If "index" does not specify a directory then the function will
  253. X * immediately return FALSE, otherwise it will return TRUE after
  254. X * processing the directory as described above.  The function may also
  255. X * return FALSE if it cannot read a new directory from the server.
  256. X */
  257. X{
  258. X    int i;
  259. X    char *path;
  260. X
  261. X    /*
  262. X     * check to see if it is a directory
  263. X     */
  264. X    if (currlevel->entry_arr[index].type != fitypDIRECTORY)
  265. X    return FALSE;
  266. X
  267. X    /*
  268. X     * check for cached directory
  269. X     */
  270. X    if (currlevel->entry_arr[index].next_level)
  271. X    {
  272. X    cache_next_dir(currlevel->entry_arr[index].name);
  273. X    currlevel = currlevel->entry_arr[index].next_level;
  274. X    }
  275. X    else
  276. X    /*
  277. X     * otherwise, load in the needed level
  278. X     */
  279. X    {
  280. X    path = cache_make_filename(currlevel->entry_arr[index].name);
  281. X    cache_next_dir(currlevel->entry_arr[index].name);
  282. X    if (!read_directory(path, &(currlevel->entry_arr[index].next_level),
  283. X        currlevel))
  284. X    {
  285. X        fprintf(stderr, "ctrl_down_dir: can't read directory!\n");
  286. X        free(path);
  287. X            cache_prev_dir();
  288. X        return FALSE;
  289. X    }
  290. X    currlevel = currlevel->entry_arr[index].next_level;
  291. X    free(path);
  292. X    }
  293. X
  294. X    /*
  295. X     * create outgoing data 
  296. X     */
  297. X    F_init_str(currlevel->num_entries);
  298. X    for (i=0; i < currlevel->num_entries; i++)
  299. X    {
  300. X    F_add_str(currlevel->entry_arr[i].line);
  301. X    }
  302. X
  303. X    return TRUE;
  304. X}
  305. X
  306. X
  307. X
  308. Xint ctrl_up_dir(void)
  309. X{
  310. X    int i;
  311. X
  312. X    /*
  313. X     * check current level
  314. X     */
  315. X    if (!currlevel->prev_level)
  316. X    {
  317. X    fprintf(stderr,"ctrl_down_dir: already at top level.\n");
  318. X    return FALSE;
  319. X    }
  320. X
  321. X    /*
  322. X     * create outgoing data
  323. X     */
  324. X    cache_prev_dir();
  325. X    currlevel = currlevel->prev_level;
  326. X
  327. X    F_init_str(currlevel->num_entries);
  328. X    for (i=0; i < currlevel->num_entries; i++)
  329. X    {
  330. X    F_add_str(currlevel->entry_arr[i].line);
  331. X    }
  332. X
  333. X    return TRUE;
  334. X}
  335. X
  336. X
  337. X/********************** ftp control **************************************/
  338. X
  339. Xvoid ctrl_set_type(int type)
  340. X/*
  341. X * Set type to either ascii or binary
  342. X */
  343. X{
  344. X    int code;
  345. X    char typec;
  346. X
  347. X    if (ftp_curr_type == type)
  348. X    return;
  349. X
  350. X    typec = (type == typASCII)? 'A' : 'I';
  351. X
  352. X    if ((code=ftp_send_command("TYPE %c", typec)) >= 300)
  353. X    {
  354. X    fprintf(stderr, "set_type: cant set type.\n");
  355. X    }
  356. X
  357. X    ftp_get_all_responses(code, response_stream);
  358. X    ftp_curr_type = type;
  359. X}
  360. X
  361. X
  362. X
  363. Xint ctrl_get_selection(char *path, int index, char *newname)
  364. X/*
  365. X * This function gets the file or directory specfied by "index".
  366. X * "path" is the retrieval path in the local file system, or 
  367. X * the current directory if NULL.  If "index" specifies a normal
  368. X * file and newname is not NULL, then the incoming file is renamed
  369. X * to "newname".
  370. X *
  371. X * Returns TRUE for success, FALSE otherwise.
  372. X */
  373. X{
  374. X    switch (currlevel->entry_arr[index].type)
  375. X    {
  376. X      case fitypFILE:
  377. X    return ctrl_get_file(path, index, newname);
  378. X    break;
  379. X
  380. X      case fitypDIRECTORY:
  381. X    return ctrl_get_directory(path, index);
  382. X    break;
  383. X
  384. X      default:
  385. X    return FALSE;
  386. X    break;
  387. X    }
  388. X}
  389. X
  390. X
  391. Xint ctrl_get_directory(char *path, int index)
  392. X/*
  393. X * This function gets the directory indicated by "index".  "Path" is
  394. X * the path in the local file system where the incoming directory 
  395. X * should be retrieved into.  If "Path" is NULL, it is assumed to be
  396. X * the current directory.
  397. X *
  398. X * Returns TRUE if success, FALSE otherwise.
  399. X */
  400. X{
  401. X    int i;
  402. X    int len;
  403. X    char *local_path;
  404. X    char *name;
  405. X    struct stat stat_buf;
  406. X
  407. X    /*
  408. X     * check file type
  409. X     */
  410. X    if (currlevel->entry_arr[index].type != fitypDIRECTORY)
  411. X    return FALSE;
  412. X
  413. X    /*
  414. X     * create a local path
  415. X     */
  416. X    name = currlevel->entry_arr[index].name;
  417. X    len = (path? strlen(path)+1 : 0) + strlen(name) + 1 ;
  418. X    local_path = (char *) malloc(len+1);
  419. X
  420. X    if (path)
  421. X    {
  422. X        strcpy(local_path, path);
  423. X    if (path[strlen(path)-1] != '/')
  424. X        strcat(local_path, "/");
  425. X    }
  426. X    else
  427. X    local_path[0] = '\0';
  428. X
  429. X    strcat(local_path, name);
  430. X
  431. X   
  432. X    /*
  433. X     * create local directory, if needed
  434. X     */
  435. X     if (stat(local_path, &stat_buf) < 0)
  436. X     /* assume that directory does not exist */
  437. X     {
  438. X    if (mkdir(local_path, 0700) < 0)
  439. X    {
  440. X        fprintf(stderr, "ctrl_get_directory: couldn't make `%s`\n",
  441. X        local_path);
  442. X        return FALSE;
  443. X    }
  444. X     }
  445. X     else
  446. X     /* check to make sure it is a directory */
  447. X     {
  448. X    if (!S_ISDIR(stat_buf.st_mode))
  449. X    {
  450. X        fprintf(stderr, "ctrl_get_directory: '%s' is not a dir.\n",
  451. X        local_path);
  452. X        return FALSE;
  453. X    }
  454. X     }
  455. X
  456. X#ifdef DEBUG
  457. X    printf("ctrl_get_directory: getting '%s' -> '%s'\n", 
  458. X    currlevel->entry_arr[index].name, local_path);
  459. X#endif
  460. X
  461. X
  462. X    /*
  463. X     * go down directory and get everything recursively
  464. X     */
  465. X    if (!ctrl_down_dir(index))
  466. X    {
  467. X    ctrl_up_dir();
  468. X    return FALSE;
  469. X    }
  470. X
  471. X    for (i=0; i <  currlevel->num_entries; i++)
  472. X    {
  473. X    ctrl_get_selection(local_path, i, NULL);
  474. X    }
  475. X
  476. X    ctrl_up_dir();
  477. X
  478. X    return TRUE;
  479. X}
  480. X
  481. X
  482. X
  483. Xint  ctrl_get_file(char *path, int index, char *newname)
  484. X/*
  485. X * This function gets the file indicated by "index".  "Path" is
  486. X * the path for the directory that the file is to be retreived in,
  487. X * or current directory if NULL.  "newname", if not NULL, indicates
  488. X * a different name for the incoming file.
  489. X *
  490. X * Returns TRUE if success, FALSE otherwise.
  491. X */
  492. X{
  493. X    int len;
  494. X    int code;
  495. X    char *local_path;
  496. X    char *rem_path;
  497. X    char *name;
  498. X    FILE *fp;
  499. X
  500. X    /*
  501. X     * check file type
  502. X     */
  503. X    if (currlevel->entry_arr[index].type != fitypFILE)
  504. X    return FALSE;
  505. X
  506. X    /*
  507. X     * create fully-qualified remote name
  508. X     */
  509. X    rem_path = cache_make_filename(currlevel->entry_arr[index].name);
  510. X
  511. X    /*
  512. X     * create a local filename (with optional path)
  513. X     */
  514. X    name = (newname? newname : currlevel->entry_arr[index].name);
  515. X
  516. X    len = (path? strlen(path)+1 : 0) + strlen(name) + 1 ;
  517. X    local_path = (char *) malloc(len+1);
  518. X
  519. X    if (path)
  520. X    {
  521. X        strcpy(local_path, path);
  522. X    if (path[strlen(path)-1] != '/')
  523. X        strcat(local_path, "/");
  524. X    }
  525. X    else
  526. X    local_path[0] = '\0';
  527. X
  528. X    strcat(local_path, name);
  529. X
  530. X#ifdef DEBUG
  531. X    printf("ctrl_get_file: getting '%s' -> '%s'\n", 
  532. X    currlevel->entry_arr[index].name, local_path);
  533. X#endif
  534. X
  535. X    /*
  536. X     * if local file already exists.... 
  537. X     */
  538. X
  539. X    /*     ------- to do -------         */
  540. X
  541. X
  542. X    /*
  543. X     * open local file, get data from remote file
  544. X     */
  545. X    if ( (fp = fopen(local_path, "w")) == NULL )
  546. X    {
  547. X    fprintf(stderr, "ctrl_get_file: can't open '%s' for writing.\n",
  548. X        local_path);
  549. X    return FALSE;
  550. X    }
  551. X
  552. X    ftp_init_dataconn();
  553. X
  554. X    if ((code=ftp_send_command("RETR %s", rem_path)) >= 300)
  555. X    {
  556. X    fprintf(stderr, "ctrl_get_file: error in RETR.\n");
  557. X        ftp_get_all_responses(code, response_stream);
  558. X        free(rem_path);
  559. X    return FALSE;
  560. X    }
  561. X    else
  562. X    {
  563. X#ifdef XGETFTP
  564. X    if (!x_data_done)
  565. X        fprintf(stderr, "x_data_done already being used!\n");
  566. X    x_data_done = 0;
  567. X#endif
  568. X        ftp_get_data(fp);
  569. X    }
  570. X
  571. X#ifdef XGETFTP
  572. X    while (!x_data_done)
  573. X    XtAppProcessEvent(app_context, XtIMAll);
  574. X#endif
  575. X
  576. X    ftp_get_all_responses(code, response_stream);
  577. X    free(rem_path);
  578. X  
  579. X    fflush(fp);
  580. X    fclose(fp);
  581. X
  582. X    return TRUE;
  583. X}
  584. X
  585. X/************************** file cache interaction ***********************/
  586. X
  587. XFILE * ctrl_view_file(int index)
  588. X/*
  589. X * If the file specified by index is a normal file, this function will
  590. X * either retrieve the file from the remote host or from the file cache,
  591. X * open it for reading, and return a pointer to the open file.  If the
  592. X * file is not cached, the file will be cached.  
  593. X *
  594. X * Returns a pointer to an open file on success, or NULL otherwise.
  595. X */
  596. X{
  597. X    FILE *fp = NULL;
  598. X    char *rem_path = NULL;
  599. X    char *cache_path = NULL;
  600. X    char *new_name = NULL;
  601. X    char *complete_name = NULL;
  602. X    struct stat stat_buf;
  603. X
  604. X    /*
  605. X     * check file type
  606. X     */
  607. X    if (currlevel->entry_arr[index].type != fitypFILE)
  608. X    return NULL;
  609. X
  610. X    /*
  611. X     * Create path and name of the local file, depending on
  612. X     * whether the user wants to cache it or not.
  613. X     */
  614. X    rem_path = cache_make_filename("");
  615. X
  616. X    if (user_prefs.cache_view)
  617. X    {
  618. X        cache_path = fc_make_cache_path(rem_path);
  619. X
  620. X        complete_name = malloc( strlen(cache_path) + 
  621. X        strlen(currlevel->entry_arr[index].name) + 2);
  622. X
  623. X        sprintf(complete_name, "%s/%s", cache_path, 
  624. X        currlevel->entry_arr[index].name);
  625. X    }
  626. X    else
  627. X    {
  628. X    cache_path = (char *) malloc(10);
  629. X    strcpy(cache_path, "/tmp");
  630. X    new_name = (char *) malloc(50);
  631. X    sprintf(new_name, "xgetftpVIEW%ld", getpid());
  632. X    complete_name = malloc(strlen(cache_path) + strlen(new_name) + 2);
  633. X    sprintf(complete_name, "%s/%s", cache_path, new_name);
  634. X    }
  635. X
  636. X    free ( rem_path );
  637. X
  638. X
  639. X    /*
  640. X     * Check actual cache to see if file present.  This only happens
  641. X     * if the user preferences "cache_view" and "reuse_view" are set.
  642. X     *
  643. X     */
  644. X    if (user_prefs.cache_view && user_prefs.reuse_view &&
  645. X    (stat(complete_name, &stat_buf)==0))
  646. X    {
  647. X    if (S_ISREG(stat_buf.st_mode))
  648. X    {
  649. X#ifdef DEBUG
  650. X        fprintf(stderr, "Reusing cached file\n");
  651. X#endif
  652. X        currlevel->entry_arr[index].fCached = 1;
  653. X    }
  654. X    }
  655. X
  656. X
  657. X    /*
  658. X     * Get and cache the file, depending on user prefs
  659. X     *
  660. X     */
  661. X    if (user_prefs.cache_view && currlevel->entry_arr[index].fCached == 0)
  662. X    {
  663. X    fc_mkdir_path(cache_path);
  664. X
  665. X    if (!ctrl_get_file(cache_path, index, NULL))
  666. X        goto done;
  667. X
  668. X    currlevel->entry_arr[index].fCached = 1;
  669. X    } 
  670. X    else if (!user_prefs.cache_view)
  671. X    {
  672. X    if (!ctrl_get_file(cache_path, index, new_name))
  673. X        goto done;
  674. X    }
  675. X
  676. X
  677. X    /*
  678. X     * open the file and return pointer
  679. X     */
  680. X    fp = fopen(complete_name, "r");
  681. X
  682. Xdone:
  683. X    if (cache_path)    free (cache_path);
  684. X    if (complete_name) free (complete_name);
  685. X    if (new_name)      free (new_name);
  686. X
  687. X    return fp;
  688. X}
  689. X
  690. Xvoid ctrl_delete_file_cache(void)
  691. X{
  692. X    fc_delete_cache();
  693. X}
  694. X
  695. X
  696. X/************************** dir cache interaction ************************/
  697. X
  698. Xvoid ctrl_save_cache(void)
  699. X{
  700. X    char *cache_path;
  701. X
  702. X    cache_path = fc_make_cache_path("DIRCACHE");
  703. X    cache_save_cache(cache_path);
  704. X    free(cache_path);
  705. X}
  706. X
  707. Xint ctrl_load_cache(void)
  708. X{
  709. X    char *cache_path;
  710. X    int res;
  711. X
  712. X    cache_path = fc_make_cache_path("DIRCACHE");
  713. X    res = cache_load_cache(cache_path);
  714. X    free(cache_path);
  715. X    return res;
  716. X}
  717. X
  718. Xint ctrl_delete_cache(void)
  719. X/*
  720. X * Deletes all cached directory information and attempts to reload
  721. X * info from the server.  Returns TRUE if successful, FALSE otherwise.
  722. X *
  723. X * NOTE: The caller should disconnect upon a FALSE return since currently
  724. X *       there is no easy recovery.... should allow recovery in future
  725. X *       versions.
  726. X */
  727. X{
  728. X    int i;
  729. X    char *s;
  730. X    char *cache_path;
  731. X
  732. X    /*
  733. X     * Get rid of all cached data
  734. X     */
  735. X    cache_path = fc_make_cache_path("DIRCACHE");
  736. X    unlink(cache_path);
  737. X    free(cache_path);
  738. X    cache_free_levels(&toplevel);
  739. X
  740. X
  741. X    /*
  742. X     * Reload top level directory info from server
  743. X     *
  744. X     * NOTE: Most of this is cut-n-pasted directly from ctrl_start_session
  745. X     *
  746. X     */
  747. X    if ( (s=server_get_root()) == NULL )
  748. X    return FALSE;
  749. X
  750. X    cache_set_root(s);
  751. X
  752. X    if (!read_directory(s, &toplevel, NULL))
  753. X    return FALSE;
  754. X
  755. X    currlevel = toplevel;
  756. X
  757. X    F_init_str(toplevel->num_entries);
  758. X    for (i=0; i < toplevel->num_entries; i++)
  759. X    {
  760. X    F_add_str(toplevel->entry_arr[i].line);
  761. X    }
  762. X
  763. X    return TRUE;
  764. X}
  765. X
  766. X
  767. X/************************** misc functions *******************************/
  768. X
  769. Xchar *server_get_root(void)
  770. X/*
  771. X * This function issues a "PWD" command to the ftp server and receives
  772. X * and parses the response to get the root directory on the server.
  773. X * Returns a pointer to the string with the root if successful, or NULL
  774. X * if an error occurs.
  775. X */
  776. X{
  777. X    FILE *tmpfile;
  778. X    FILE *old_stream;
  779. X    char *s, *t;
  780. X    char filename[100];
  781. X    static char root[100];
  782. X
  783. X    sprintf(filename, "/tmp/xgetftpROOT%ld", getpid());
  784. X    if ( (tmpfile = fopen(filename, "w+")) == NULL )
  785. X    {
  786. X    fprintf(stderr, "server_get_root: can't open '%s'.\n", filename);
  787. X    return NULL;
  788. X    }
  789. X
  790. X    old_stream = response_stream;
  791. X    response_stream = tmpfile;
  792. X
  793. X    if (ftp_send_command("PWD") >= 300)
  794. X    {
  795. X    fprintf(stderr, "server_get_root: cant get PWD\n");
  796. X    unlink(filename);
  797. X    response_stream = old_stream;
  798. X    return NULL;
  799. X    }
  800. X
  801. X    response_stream = old_stream;
  802. X
  803. X    fseek(tmpfile, 0, 0);
  804. X    fgets(root, 98, tmpfile);
  805. X
  806. X    s = root;
  807. X    while (*s && *s++ !='"');
  808. X    t = s;
  809. X    while (*t && *++t !='"');
  810. X    *t = '\0';
  811. X    fclose(tmpfile);
  812. X
  813. X#ifdef DEBUG
  814. X    printf("server_get_root on: root = '%s'\n", s);
  815. X#endif
  816. X
  817. X    return s;
  818. X}
  819. X
  820. X
  821. Xchar *ctrl_get_item_name(int item)
  822. X/*
  823. X * This function returns a string that specifies the complete path of
  824. X * the selected item.   If item < 0, then the complete path of the
  825. X * current directory is returned.
  826. X *
  827. X * Returns a string (which should be freed later by caller), or NULL
  828. X * if the item number is too large.
  829. X *
  830. X */
  831. X{
  832. X    char * curr_path = NULL;
  833. X
  834. X    if (item < 0)
  835. X        curr_path = cache_make_filename("");
  836. X    else if (item < currlevel->num_entries)
  837. X    curr_path = cache_make_filename(currlevel->entry_arr[item].name);
  838. X
  839. X    return curr_path;
  840. X}
  841. X
  842. X
  843. X
  844. Xvoid x_get_data(FILE *fdout, int *fid, XtInputId *id)
  845. X/* data input callback */
  846. X{
  847. X    unsigned char buf[INBUFSIZE];
  848. X    int nbytes;
  849. X
  850. X    nbytes = read(*fid, buf, INBUFSIZE);
  851. X
  852. X    if (nbytes)
  853. X    {
  854. X    write(fileno(fdout), buf, nbytes);    
  855. X    }
  856. X    else
  857. X    /* EOF reached */
  858. X    {
  859. X    x_data_done = 1;
  860. X    XtRemoveInput(*id);
  861. X    close(*fid);
  862. X    }
  863. X}
  864. X
  865. X
  866. Xint read_directory(char *path, cacheinfo_ptr *plevel, cacheinfo_ptr prev)
  867. X{
  868. X    char filename[100];
  869. X    FILE *tmpfile;
  870. X    int code;
  871. X
  872. X#ifdef DEBUG
  873. X    printf("read_directory: Reading from path: '%s'\n", path);
  874. X#endif
  875. X
  876. X    ftp_init_dataconn();
  877. X    sprintf(filename, "/tmp/xgetftpLISTING%ld", getpid());
  878. X    if ( (tmpfile = fopen(filename, "w")) == NULL )
  879. X    {
  880. X    fprintf(stderr, "read_directory: can't open '%s'.\n", filename);
  881. X    return FALSE;
  882. X    }
  883. X
  884. X    if ((code=ftp_send_command("LIST %s", path)) >= 300)
  885. X    {
  886. X    fprintf(stderr, "read_directory: can't get LIST.\n");
  887. X    unlink(filename);
  888. X    return FALSE;
  889. X    }
  890. X
  891. X#ifdef XGETFTP
  892. X    if (!x_data_done)
  893. X    fprintf(stderr, "x_data_done already being used!\n");
  894. X    x_data_done = 0;
  895. X#endif
  896. X
  897. X    ftp_get_data(tmpfile);
  898. X
  899. X#ifdef XGETFTP
  900. X    while (!x_data_done)
  901. X    XtAppProcessEvent(app_context, XtIMAll);
  902. X#endif
  903. X
  904. X    ftp_get_all_responses(code, response_stream);
  905. X    fclose(tmpfile);
  906. X
  907. X    cache_init_level(plevel, prev, filename);
  908. X#ifdef DEBUG
  909. X    cache_print_level(*plevel);
  910. X#endif
  911. X
  912. X    unlink(filename);
  913. X    return TRUE;
  914. X}
  915. X
  916. END_OF_FILE
  917. if test 19375 -ne `wc -c <'control.c'`; then
  918.     echo shar: \"'control.c'\" unpacked with wrong size!
  919. fi
  920. # end of 'control.c'
  921. fi
  922. if test -f 'control.h' -a "${1}" != "-c" ; then 
  923.   echo shar: Will not clobber existing file \"'control.h'\"
  924. else
  925. echo shar: Extracting \"'control.h'\" \(1310 characters\)
  926. sed "s/^X//" >'control.h' <<'END_OF_FILE'
  927. X/************************************************************************
  928. X * HEADER:
  929. X *  control
  930. X ***********************************************************************/
  931. X
  932. X/*
  933. X * FTP Type definitions
  934. X */
  935. X#define typASCII    0
  936. X#define typIMAGE    1
  937. X
  938. Xextern int ftp_curr_type;
  939. X
  940. X
  941. X/*
  942. X * CreateFunc is a pointer to a function that takes a string
  943. X * and returns a void.  This function will be called once for
  944. X * every string in a given directory.  It should have an internal
  945. X * state that keeps track of the strings. 
  946. X *
  947. X * InitFunc allocates the memory needed.  Its parameter is the
  948. X * number of items that will need to be created.
  949. X *
  950. X */
  951. Xtypedef void (*CreateFunc) (char *);
  952. Xtypedef void (*InitFunc) (int);
  953. X
  954. X/*
  955. X * Prototypes
  956. X */
  957. Xint
  958. Xctrl_login(char *host, char *user, char *pass);
  959. X
  960. Xint
  961. Xctrl_start_session(InitFunc init_str, CreateFunc add_str);
  962. X
  963. Xint
  964. Xctrl_down_dir(int index);
  965. X
  966. Xint
  967. Xctrl_up_dir(void);
  968. X
  969. Xvoid
  970. Xctrl_set_type(int);
  971. X
  972. Xint 
  973. Xctrl_get_selection(char *path, int index, char *newname);
  974. X
  975. Xint 
  976. Xctrl_get_file(char *path, int index, char *newname);
  977. X
  978. XFILE *
  979. Xctrl_view_file(int index);
  980. X
  981. Xint 
  982. Xctrl_get_directory(char *path, int index);
  983. X
  984. Xvoid
  985. Xctrl_logout(void);
  986. X
  987. Xvoid 
  988. Xctrl_save_cache(void);
  989. X
  990. Xint
  991. Xctrl_load_cache(void);
  992. X
  993. Xint
  994. Xctrl_delete_cache(void);
  995. X
  996. Xchar *
  997. Xctrl_get_item_name(int item);
  998. X
  999. Xvoid
  1000. Xctrl_delete_file_cache(void);
  1001. X
  1002. END_OF_FILE
  1003. if test 1310 -ne `wc -c <'control.h'`; then
  1004.     echo shar: \"'control.h'\" unpacked with wrong size!
  1005. fi
  1006. # end of 'control.h'
  1007. fi
  1008. if test -f 'file_cache.c' -a "${1}" != "-c" ; then 
  1009.   echo shar: Will not clobber existing file \"'file_cache.c'\"
  1010. else
  1011. echo shar: Extracting \"'file_cache.c'\" \(4853 characters\)
  1012. sed "s/^X//" >'file_cache.c' <<'END_OF_FILE'
  1013. X/***************************************************************************
  1014. X *
  1015. X * MODULE:
  1016. X *  file cache
  1017. X *
  1018. X * DESCRIPTION
  1019. X *  Provides functions used to maintain a cache of files "Viewed" by
  1020. X *  xgetftp.
  1021. X *
  1022. X * AUTHOR:
  1023. X *  Salim Alam
  1024. X *  University of Colorado, Boulder
  1025. X *
  1026. X * MODIFICATION LOG:
  1027. X *  92.12.29 S.A. - Added file cache delete function
  1028. X *
  1029. X **************************************************************************/
  1030. X
  1031. X#include <stdio.h>
  1032. X#include <X11/Xos.h>
  1033. X#include <sys/stat.h>
  1034. X#include <malloc.h>
  1035. X#include <stdlib.h> 
  1036. X#include <dirent.h>
  1037. X
  1038. X#ifndef TRUE
  1039. X#define TRUE 1
  1040. X#define FALSE 0
  1041. X#endif
  1042. X
  1043. X#define PRIVATE static
  1044. X
  1045. X
  1046. X/*
  1047. X * Private global variables
  1048. X */
  1049. X
  1050. X#define DEFAULT_CACHE_DIR ".xgetftpcachedir"
  1051. X
  1052. XPRIVATE char * cache_root;
  1053. X
  1054. X
  1055. X
  1056. Xvoid fc_set_root_dir(char *hostname)
  1057. X/*
  1058. X * This function determines the directory in the user's filespace
  1059. X * where the cache hierarchy should be organized.  First the env
  1060. X * variable XGETFTPCACHEDIR is checked --- if available, it will be
  1061. X * used.  Otherwise, the env var HOME will be looked up and the directory
  1062. X * $HOME/.xgetftpcachedir will be used.  If the HOME var cannot be found,
  1063. X * the current working directory will be used.
  1064. X *
  1065. X * After determining the cache directory, this function saves the name
  1066. X * of the host and appends it to the cache directory path.  All files
  1067. X * cached in this session will now be cached here.
  1068. X *
  1069. X */
  1070. X{
  1071. X    int len;
  1072. X    char *tmp_str;
  1073. X
  1074. X  
  1075. X    /*
  1076. X     * Create cache root
  1077. X     */
  1078. X    if (tmp_str = getenv("XGETFTPCACHEDIR"))
  1079. X    {
  1080. X    len = strlen(tmp_str);
  1081. X    cache_root = malloc(len + strlen(hostname) + 2);
  1082. X    if (tmp_str[len] == '/')
  1083. X        sprintf(cache_root, "%s%s", tmp_str, hostname);
  1084. X    else
  1085. X        sprintf(cache_root, "%s/%s", tmp_str, hostname);
  1086. X    }
  1087. X    else if (tmp_str = getenv("HOME"))
  1088. X    {
  1089. X        len = strlen(tmp_str) + strlen(DEFAULT_CACHE_DIR) + 2;
  1090. X        cache_root = malloc ( len + strlen(hostname) );
  1091. X        sprintf(cache_root, "%s/%s/%s", tmp_str, DEFAULT_CACHE_DIR, hostname);
  1092. X    }
  1093. X    else
  1094. X    {
  1095. X    tmp_str = (char *) getcwd(NULL, 256);
  1096. X        len = strlen(tmp_str) + strlen(DEFAULT_CACHE_DIR) + 2;
  1097. X        cache_root = malloc ( len + strlen(hostname) );
  1098. X        sprintf(cache_root, "%s/%s/%s", tmp_str, DEFAULT_CACHE_DIR, hostname);
  1099. X    }
  1100. X
  1101. X#ifdef DEBUG
  1102. X        fprintf(stderr, "Cache root = '%s'\n", cache_root);
  1103. X#endif
  1104. X
  1105. X}
  1106. X
  1107. X
  1108. X
  1109. X
  1110. Xchar * fc_make_cache_path(char *rem_path)
  1111. X/*
  1112. X * Given the remote path for a file (NOT including the file name), this
  1113. X * function appends the remote path to the cache_root and returns a pointer
  1114. X * to the complete path.  Memory is allocated, so the pointer returned should
  1115. X * be eventually freed by the caller.
  1116. X *
  1117. X */
  1118. X{
  1119. X    char *complete_path;
  1120. X
  1121. X    complete_path = malloc(strlen(rem_path) + strlen(cache_root) + 2);
  1122. X
  1123. X    if (rem_path[0] == '/')
  1124. X        sprintf(complete_path, "%s%s", cache_root, rem_path);
  1125. X    else
  1126. X        sprintf(complete_path, "%s/%s", cache_root, rem_path);
  1127. X
  1128. X    return complete_path;
  1129. X}
  1130. X
  1131. X
  1132. X
  1133. Xint fc_mkdir_path(char *path)
  1134. X/*
  1135. X * Given a complete path in the user's file system, this function makes
  1136. X * sure that all the directories in the path are present.  This function
  1137. X * will call "mkdir" to create any needed directories.
  1138. X *
  1139. X * Returns TRUE for success, FALSE otherwise.
  1140. X *
  1141. X */
  1142. X{
  1143. X    char *s;
  1144. X    struct stat stat_buf;
  1145. X
  1146. X    /*
  1147. X     * First, check the complete path at once
  1148. X     */
  1149. X    if (stat(path, &stat_buf) == 0)    
  1150. X    {
  1151. X    if (!S_ISDIR(stat_buf.st_mode))
  1152. X    {
  1153. X        fprintf(stderr, "ctrl_get_directory: '%s' is not a dir.\n",
  1154. X        path);
  1155. X        return FALSE;
  1156. X    }
  1157. X    return TRUE;
  1158. X    }
  1159. X
  1160. X
  1161. X    /*
  1162. X     * Now check component-wise
  1163. X     */
  1164. X    s = path;
  1165. X    while (*s)
  1166. X    {
  1167. X    while ((*s) && (*s != '/')) s++;
  1168. X    if (*s == '/')
  1169. X    /* check component */
  1170. X    {
  1171. X        *s = '\0';
  1172. X#ifdef DEBUG
  1173. X        fprintf(stderr,"fc_mkdir_path: Checking '%s'\n", path);
  1174. X#endif
  1175. X        if (stat(path, &stat_buf) < 0)
  1176. X        /* assume file didn't exist */
  1177. X        {
  1178. X#ifdef DEBUG
  1179. X        fprintf(stderr,"fc_mkdir_path: Making '%s'\n", path);
  1180. X#endif
  1181. X        if (mkdir(path, 0700) < 0)
  1182. X        {
  1183. X             fprintf(stderr, "fc_mkdir_path: couldn't make `%s`\n",
  1184. X            path);
  1185. X             return FALSE;
  1186. X        }
  1187. X        }
  1188. X        else
  1189. X        /* check to make sure this is a dir */
  1190. X        {
  1191. X        if (!S_ISDIR(stat_buf.st_mode))
  1192. X        {
  1193. X            fprintf(stderr, "ctrl_get_directory: '%s' is not a dir.\n",
  1194. X            path);
  1195. X            return FALSE;
  1196. X        }
  1197. X        }
  1198. X        *s = '/';
  1199. X        s++;
  1200. X    } /* while */
  1201. X
  1202. X    } /* while */
  1203. X}
  1204. X
  1205. X
  1206. Xint fc_delete_cache(void)
  1207. X/*
  1208. X * Deletes the file viewed cache
  1209. X */
  1210. X{
  1211. X    DIR *dir;
  1212. X    struct dirent * entry;
  1213. X    char command_str[255];
  1214. X
  1215. X    if ( (dir = opendir(cache_root)) == NULL )
  1216. X    return FALSE;
  1217. X
  1218. X    while ( (entry = readdir(dir)) != NULL )
  1219. X    {
  1220. X    if ( (strcmp(entry->d_name, ".")==0) ||
  1221. X         (strcmp(entry->d_name, "..")==0) ||
  1222. X         (strcmp(entry->d_name, "DIRCACHE")==0) )
  1223. X        continue;
  1224. X
  1225. X    sprintf(command_str, "/bin/rm -rf %s/%s", cache_root, entry->d_name);
  1226. X
  1227. X    system(command_str);
  1228. X    }
  1229. X
  1230. X    closedir(dir);
  1231. X}
  1232. X
  1233. END_OF_FILE
  1234. if test 4853 -ne `wc -c <'file_cache.c'`; then
  1235.     echo shar: \"'file_cache.c'\" unpacked with wrong size!
  1236. fi
  1237. # end of 'file_cache.c'
  1238. fi
  1239. if test -f 'file_cache.h' -a "${1}" != "-c" ; then 
  1240.   echo shar: Will not clobber existing file \"'file_cache.h'\"
  1241. else
  1242. echo shar: Extracting \"'file_cache.h'\" \(331 characters\)
  1243. sed "s/^X//" >'file_cache.h' <<'END_OF_FILE'
  1244. X/***************************************************************************
  1245. X *
  1246. X * HEADER:
  1247. X *  file cache
  1248. X *
  1249. X **************************************************************************/
  1250. X
  1251. Xvoid
  1252. Xfc_set_root_dir(char *hostname);
  1253. X
  1254. Xchar * 
  1255. Xfc_make_cache_path(char *rem_path);
  1256. X
  1257. Xint
  1258. Xfc_mkdir_path(char *path);
  1259. X
  1260. Xint
  1261. Xfc_delete_cache(void);
  1262. X
  1263. END_OF_FILE
  1264. if test 331 -ne `wc -c <'file_cache.h'`; then
  1265.     echo shar: \"'file_cache.h'\" unpacked with wrong size!
  1266. fi
  1267. # end of 'file_cache.h'
  1268. fi
  1269. if test -f 'ftp.c' -a "${1}" != "-c" ; then 
  1270.   echo shar: Will not clobber existing file \"'ftp.c'\"
  1271. else
  1272. echo shar: Extracting \"'ftp.c'\" \(8569 characters\)
  1273. sed "s/^X//" >'ftp.c' <<'END_OF_FILE'
  1274. X/*=========================================================================
  1275. X * MODULE:
  1276. X *  "ftp"
  1277. X *
  1278. X * DESCRIPTION:
  1279. X *  Provides a FTP interface for a client program.  
  1280. X *
  1281. X * AUTHOR:
  1282. X *  Salim Alam
  1283. X *  University of Colorado, Boulder
  1284. X *
  1285. X * MODIFICATION LOG:
  1286. X *  93.01.14 S.A. - fixed return bug in ftp_init_conn
  1287. X *  92.12.29 S.A. - ftp_init_conn now handles some errors more gracefully.
  1288. X *            also, better use of "reponse_stream".
  1289. X *  92.12.01 S.A. - fixed response bug by making buffer larger
  1290. X *  92.11.24 S.A. - adding functionality to allow X-based I/O
  1291. X *  92.10.28 S.A. - ftp_get_response : better multi-line response handling.
  1292. X *=======================================================================*/
  1293. X
  1294. X#include <X11/Xos.h>
  1295. X#include <stdio.h>
  1296. X#include <sys/socket.h>
  1297. X#include <netinet/in.h>
  1298. X#include <arpa/inet.h>
  1299. X#include <netdb.h>
  1300. X#include <errno.h>
  1301. X#include <stdarg.h>
  1302. X
  1303. X/* Special stuff for X-based I/O */
  1304. X#define XGETFTP
  1305. X
  1306. X#ifdef XGETFTP
  1307. X#include <X11/Intrinsic.h>
  1308. Xextern void x_get_data(caddr_t, int *, XtInputId *);
  1309. Xextern XtAppContext app_context;
  1310. X#endif
  1311. X
  1312. X
  1313. X/* telnet codes */
  1314. X#define tcSE     240
  1315. X#define tcNOP    241
  1316. X#define tcDM    242
  1317. X#define tcBRK    243
  1318. X#define tcIP    244
  1319. X#define tcAO    245
  1320. X#define tcAYT    246
  1321. X#define tcEC    247
  1322. X#define tcEL    248
  1323. X#define tcGA    249
  1324. X#define tcSB    250
  1325. X#define tcWILL    251
  1326. X#define tcWONT    252
  1327. X#define tcDO    253
  1328. X#define tcDONT    254
  1329. X#define tcIAC    255
  1330. X
  1331. X/* other misc defines */
  1332. X#define typeASCII        0
  1333. X#define typeIMAGE        1
  1334. X#define FTP_SERVER_PORTNUM    21    /* hardcoded, for now         */
  1335. X
  1336. X#ifndef TRUE
  1337. X#define TRUE 1
  1338. X#define FALSE 0
  1339. X#endif
  1340. X
  1341. X#define PRIVATE static
  1342. X#define UC(b) (((int)b)&0xff)
  1343. X#define err_die(z) {perror(z); exit(1);}
  1344. X
  1345. X#define RESP_BUFSIZE        256    /* buffer size, for a response line */
  1346. X
  1347. X/*
  1348. X * Exported Variables
  1349. X */
  1350. XFILE *response_stream = stdout;
  1351. X
  1352. X
  1353. X/*
  1354. X * Global Variables
  1355. X */
  1356. XPRIVATE FILE *responsefp;    /* response stream            */
  1357. XPRIVATE FILE *commandfp;    /* command stream            */
  1358. XPRIVATE FILE *datainfp;        /* data input stream            */
  1359. XPRIVATE FILE *dataoutfp;    /* data output stream            */
  1360. XPRIVATE int sd_ctrl;        /* socket descr. for control connection */
  1361. XPRIVATE int sd_data;        /* socket descr. for initial data conn.    */
  1362. XPRIVATE struct sockaddr_in ctrl_addr; /* address for server        */
  1363. XPRIVATE struct sockaddr_in my_addr;   /* address for client        */
  1364. XPRIVATE int  type;        /* Image or Ascii            */
  1365. X
  1366. X
  1367. Xint ftp_init_conn(char *hostname)
  1368. X/*
  1369. X * Attempts a connection to the FTP port on the remote server "hostname".
  1370. X * Hostname _must_ be a name, not an IP number. 
  1371. X *
  1372. X * Dies if any serious errors encountered.
  1373. X *
  1374. X * Returns TRUE on success, FALSE otherwise.
  1375. X */
  1376. X{
  1377. X    int len;
  1378. X    struct hostent *hp;
  1379. X
  1380. X    /*
  1381. X     * open primary socket connection 
  1382. X     */
  1383. X    if ((sd_ctrl = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  1384. X    err_die("ftp_init_conn ctrl socket");
  1385. X
  1386. X    /*
  1387. X     * find description of host & set up it's address
  1388. X     *
  1389. X     * NOTE: only actual names are allowed here.. no provision
  1390. X     *       for checking numbers...
  1391. X     */
  1392. X    if ((hp = gethostbyname(hostname)) == 0)
  1393. X    {
  1394. X    close(sd_ctrl);
  1395. X    return FALSE;
  1396. X    }
  1397. X
  1398. X    bzero((char *)&ctrl_addr, sizeof(ctrl_addr));
  1399. X    bcopy(hp->h_addr, &ctrl_addr.sin_addr, hp->h_length);
  1400. X    ctrl_addr.sin_family = AF_INET;
  1401. X    ctrl_addr.sin_port = htons(FTP_SERVER_PORTNUM);
  1402. X
  1403. X    /*
  1404. X     * establish a connection
  1405. X     */
  1406. X    if (connect(sd_ctrl, (struct sockaddr *)&ctrl_addr, sizeof(ctrl_addr)) < 0)
  1407. X    {
  1408. X    close(sd_ctrl);
  1409. X    return FALSE;
  1410. X    }
  1411. X
  1412. X    /*
  1413. X     * open stream descriptors, to make variable arg handling
  1414. X     * easy.
  1415. X     */
  1416. X    responsefp = fdopen(sd_ctrl, "r");
  1417. X    commandfp  = fdopen(sd_ctrl, "w");
  1418. X
  1419. X
  1420. X    /*
  1421. X     * find out about client's port
  1422. X     */
  1423. X    len = sizeof(my_addr);
  1424. X    if (getsockname(sd_ctrl, (struct sockaddr *)&my_addr, &len) < 0)
  1425. X    err_die("ftp_init_data getsockname my_addr");
  1426. X
  1427. X    return TRUE;
  1428. X}
  1429. X
  1430. X
  1431. X
  1432. Xint ftp_send_command(char *fmt, ...)
  1433. X/*
  1434. X * Sends a command to the server.  The input parameters are in a
  1435. X * "printf" form --- ie, a format specification string, followed
  1436. X * by a variable number of arguments.
  1437. X *
  1438. X * After sending command, gets the appropriate number of responses
  1439. X * from the server.  Gets a SINGLE response from the server and
  1440. X * returns the response code.
  1441. X *
  1442. X * For multiple-response commands, further responses need to be
  1443. X * checked for by the server.
  1444. X */ 
  1445. X{
  1446. X    va_list ap;
  1447. X
  1448. X#ifdef DEBUG
  1449. X    fprintf(stderr,"Sending: ");
  1450. X    va_start(ap, fmt);
  1451. X    vfprintf(stderr, fmt, ap);
  1452. X    va_end(ap);
  1453. X    fprintf(stderr, "\n");
  1454. X#endif
  1455. X
  1456. X    va_start(ap, fmt);
  1457. X    vfprintf(commandfp, fmt, ap);
  1458. X    va_end(ap);
  1459. X    fprintf(commandfp, "\r\n");
  1460. X    (void) fflush(commandfp);
  1461. X
  1462. X    return (ftp_get_response(response_stream));
  1463. X}
  1464. X
  1465. X
  1466. X
  1467. Xint ftp_get_response(FILE *fdout)
  1468. X/*
  1469. X * Gets a single response from the server thru the command connection.
  1470. X * Multiple-line responses are handled.  The complete text of the
  1471. X * responses are written to the file fdout, which should be open and
  1472. X * ready for writing.  ALL TELNET CONTROLS ARE IGNORED.
  1473. X *
  1474. X * The response code is returned.
  1475. X */
  1476. X{
  1477. X    int code, test_code = 0;
  1478. X    char continue_flag;
  1479. X    char line[RESP_BUFSIZE];
  1480. X
  1481. X    fgets(line, RESP_BUFSIZE-2, responsefp);
  1482. X    fprintf(fdout, line);
  1483. X#ifdef DEBUG
  1484. X    if (strchr(line,tcIAC) != NULL)
  1485. X    fprintf(stderr,"<ignoring Telnet IAC>\n");
  1486. X#endif
  1487. X
  1488. X    continue_flag = line[3];
  1489. X    line[3] = '\0';
  1490. X    code = atoi(line);
  1491. X
  1492. X    if (continue_flag == '-')
  1493. X    {
  1494. X    while (test_code != code)
  1495. X    {
  1496. X        fgets(line, RESP_BUFSIZE-2, responsefp);
  1497. X        fprintf(fdout, line);
  1498. X        if (line[3] == '-') continue;
  1499. X        line[3] = '\0';
  1500. X        test_code = atoi(line);
  1501. X    }
  1502. X    }
  1503. X
  1504. X    fflush(fdout);
  1505. X    return code;
  1506. X}
  1507. X
  1508. X
  1509. X
  1510. Xint ftp_get_next_response(int oldcode, FILE *fdout)
  1511. X/*
  1512. X * Given the previous response code, gets any expected responses
  1513. X * from the server.  If no more expected responses, returns -1,
  1514. X * else returns the code for the response it got.
  1515. X */
  1516. X{
  1517. X    if ( ((int) (oldcode/100.0))  == 1 )
  1518. X    return (ftp_get_response(fdout));
  1519. X    else
  1520. X    return -1;
  1521. X}
  1522. X
  1523. X
  1524. X
  1525. Xvoid ftp_get_all_responses(int code, FILE *fdout)
  1526. X/*
  1527. X * Gets all further remaining responses from the server.  If
  1528. X * code is equal to 0, then an initial response will get gotten
  1529. X * from the server;  otherwise, code will be assumed to be the
  1530. X * result of a previous ftp_get_response command.
  1531. X */
  1532. X{
  1533. X    int nextcode = code;
  1534. X
  1535. X    if (code == 0)
  1536. X    nextcode = ftp_get_response(fdout);
  1537. X
  1538. X    while ( (nextcode=ftp_get_next_response(nextcode,fdout)) > 0 ) ;
  1539. X}
  1540. X
  1541. X
  1542. X
  1543. Xint ftp_init_dataconn(void)
  1544. X/*
  1545. X * Creates a new port for data connections, and sends a PORT command
  1546. X * to the server. Starts listening on the newly created port.
  1547. X *
  1548. X * All errors are fatal!  Return is positive integer.
  1549. X */
  1550. X{
  1551. X    int len, result;
  1552. X    struct sockaddr_in data_addr;
  1553. X    char *p, *a;
  1554. X
  1555. X
  1556. X    /*
  1557. X     * create a new port & start listening
  1558. X     */
  1559. X    data_addr = my_addr;
  1560. X    data_addr.sin_port = 0;    /* system picks a port */
  1561. X
  1562. X    if ( (sd_data = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  1563. X    err_die("ftp_init_dataconn data socket");
  1564. X  
  1565. X    if (bind(sd_data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0)
  1566. X    err_die("ftp_init_dataconn bind");
  1567. X
  1568. X    len = sizeof(data_addr);
  1569. X    if (getsockname(sd_data, (struct sockaddr *)&data_addr, &len) < 0)
  1570. X    err_die("ftp_init_dataconn getsockname");
  1571. X
  1572. X    listen(sd_data, 5);
  1573. X
  1574. X    /*
  1575. X     * send PORT command to server
  1576. X     */
  1577. X    p = (char *)&data_addr.sin_port;
  1578. X    a = (char *)&data_addr.sin_addr;
  1579. X
  1580. X    result = ftp_send_command("PORT %d,%d,%d,%d,%d,%d",
  1581. X    UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),UC(p[0]),UC(p[1]) );
  1582. X
  1583. X    return result;
  1584. X}
  1585. X
  1586. X
  1587. X
  1588. Xint ftp_get_data(FILE *fdout)
  1589. X/*
  1590. X * Gets a file from the data connection.  The data port should be listening
  1591. X * for an incoming connection.  The data file is written to the stream fdout,
  1592. X * which should already be open and ready for writing. A stream data
  1593. X * connection mode is assumed.
  1594. X *
  1595. X * Returns void.
  1596. X */
  1597. X{
  1598. X    int fromlen = 0;
  1599. X    int c, s;
  1600. X
  1601. X    /*
  1602. X     * Establish a connection with server data port
  1603. X     */
  1604. X    s = accept(sd_data, (struct sockaddr *)NULL, &fromlen);
  1605. X    datainfp = fdopen(s, "r");
  1606. X
  1607. X#ifdef XGETFTP
  1608. X    /*
  1609. X     * Set up Xt routines for getting input.  x_get_data is
  1610. X     * an external function that must be provided.
  1611. X     */
  1612. X    XtAppAddInput(app_context, s, (XtPointer) XtInputReadMask, 
  1613. X    (XtInputCallbackProc) x_get_data, (XtPointer) fdout);
  1614. X#else
  1615. X    /*
  1616. X     * Read in & echo the input
  1617. X     */
  1618. X    while ((c = getc(datainfp)) != EOF)
  1619. X    (void) putc(c, fdout);
  1620. X
  1621. X    close(s);
  1622. X#endif
  1623. X
  1624. X}
  1625. X
  1626. X
  1627. X
  1628. Xint ftp_put_data(FILE *fdout)
  1629. X/* stub */
  1630. X{
  1631. X    fprintf(stderr, "STUB ftp_put_data called!\n");
  1632. X}
  1633. X
  1634. X
  1635. X
  1636. Xvoid ftp_close_conn(void)
  1637. X/*
  1638. X * Close the connection to the ftp server
  1639. X */
  1640. X{
  1641. X    close(sd_ctrl);
  1642. X    close(sd_data);
  1643. X}
  1644. END_OF_FILE
  1645. if test 8569 -ne `wc -c <'ftp.c'`; then
  1646.     echo shar: \"'ftp.c'\" unpacked with wrong size!
  1647. fi
  1648. # end of 'ftp.c'
  1649. fi
  1650. if test -f 'ftp.h' -a "${1}" != "-c" ; then 
  1651.   echo shar: Will not clobber existing file \"'ftp.h'\"
  1652. else
  1653. echo shar: Extracting \"'ftp.h'\" \(631 characters\)
  1654. sed "s/^X//" >'ftp.h' <<'END_OF_FILE'
  1655. X/*=========================================================================
  1656. X * HEADER:
  1657. X *  "ftp"
  1658. X *=======================================================================*/
  1659. X
  1660. X/*
  1661. X * Exported variables
  1662. X */
  1663. X
  1664. Xextern FILE *response_stream;    /* where the response should go --
  1665. X                   normally it should go to stdout */
  1666. X
  1667. X
  1668. X/*
  1669. X * Function prototypes.
  1670. X */
  1671. X
  1672. Xint
  1673. Xftp_init_conn(char *hostname);
  1674. X
  1675. Xint
  1676. Xftp_send_command(char *fmt, ...);
  1677. X
  1678. Xint
  1679. Xftp_get_response(FILE *fdout);
  1680. X
  1681. Xint
  1682. Xftp_get_next_response(int oldcode, FILE *fdout);
  1683. X
  1684. Xint
  1685. Xftp_init_dataconn(void);
  1686. X
  1687. Xint
  1688. Xftp_get_data(FILE *fdout);
  1689. X
  1690. Xint
  1691. Xftp_put_data(FILE *fdout);
  1692. X
  1693. Xvoid
  1694. Xftp_close_conn(void);
  1695. END_OF_FILE
  1696. if test 631 -ne `wc -c <'ftp.h'`; then
  1697.     echo shar: \"'ftp.h'\" unpacked with wrong size!
  1698. fi
  1699. # end of 'ftp.h'
  1700. fi
  1701. echo shar: End of archive 2 \(of 4\).
  1702. cp /dev/null ark2isdone
  1703. MISSING=""
  1704. for I in 1 2 3 4 ; do
  1705.     if test ! -f ark${I}isdone ; then
  1706.     MISSING="${MISSING} ${I}"
  1707.     fi
  1708. done
  1709. if test "${MISSING}" = "" ; then
  1710.     echo You have unpacked all 4 archives.
  1711.     rm -f ark[1-9]isdone
  1712. else
  1713.     echo You still need to unpack the following archives:
  1714.     echo "        " ${MISSING}
  1715. fi
  1716. ##  End of shell archive.
  1717. exit 0
  1718.  
  1719. exit 0 # Just in case...
  1720. -- 
  1721.   // chris@IMD.Sterling.COM            | Send comp.sources.x submissions to:
  1722. \X/  Amiga - The only way to fly!      |
  1723.  "It's intuitively obvious to the most |    sources-x@imd.sterling.com
  1724.   casual observer..."                  |
  1725.