Annotation of embedaddon/php/ext/ftp/ftp.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Authors: Andrew Skalski <askalski@chek.com>                          |
                     16:    |          Stefan Esser <sesser@php.net> (resume functions)            |
                     17:    +----------------------------------------------------------------------+
                     18:  */
                     19: 
                     20: /* $Id: ftp.c 321634 2012-01-01 13:15:04Z felipe $ */
                     21: 
                     22: #ifdef HAVE_CONFIG_H
                     23: #include "config.h"
                     24: #endif
                     25: 
                     26: #include "php.h"
                     27: 
                     28: #if HAVE_FTP
                     29: 
                     30: #include <stdio.h>
                     31: #include <ctype.h>
                     32: #include <stdlib.h>
                     33: #ifdef HAVE_UNISTD_H
                     34: #include <unistd.h>
                     35: #endif
                     36: #include <fcntl.h>
                     37: #include <string.h>
                     38: #include <time.h>
                     39: #ifdef PHP_WIN32
                     40: #include <winsock2.h>
                     41: #elif defined(NETWARE)
                     42: #ifdef USE_WINSOCK    /* Modified to use Winsock (NOVSOCK2.H), atleast for now */
                     43: #include <novsock2.h>
                     44: #else
                     45: #include <sys/socket.h>
                     46: #include <netinet/in.h>
                     47: #include <netdb.h>
                     48: #endif
                     49: #else
                     50: #ifdef HAVE_SYS_TYPES_H
                     51: #include <sys/types.h>
                     52: #endif
                     53: #include <sys/socket.h>
                     54: #include <netinet/in.h>
                     55: #include <arpa/inet.h>
                     56: #include <netdb.h>
                     57: #endif
                     58: #include <errno.h>
                     59: 
                     60: #if HAVE_SYS_TIME_H
                     61: #include <sys/time.h>
                     62: #endif
                     63: 
                     64: #ifdef HAVE_SYS_SELECT_H
                     65: #include <sys/select.h>
                     66: #endif
                     67: 
                     68: #if HAVE_OPENSSL_EXT
                     69: #include <openssl/ssl.h>
                     70: #endif
                     71: 
                     72: #include "ftp.h"
                     73: #include "ext/standard/fsock.h"
                     74: 
                     75: /* Additional headers for NetWare */
                     76: #if defined(NETWARE) && !defined(USE_WINSOCK)
                     77: #include <sys/select.h>
                     78: #endif
                     79: 
                     80: /* sends an ftp command, returns true on success, false on error.
                     81:  * it sends the string "cmd args\r\n" if args is non-null, or
                     82:  * "cmd\r\n" if args is null
                     83:  */
                     84: static int             ftp_putcmd(     ftpbuf_t *ftp,
                     85:                                        const char *cmd,
                     86:                                        const char *args);
                     87: 
                     88: /* wrapper around send/recv to handle timeouts */
                     89: static int             my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len);
                     90: static int             my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len);
                     91: static int             my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen);
                     92: 
                     93: /* reads a line the socket , returns true on success, false on error */
                     94: static int             ftp_readline(ftpbuf_t *ftp);
                     95: 
                     96: /* reads an ftp response, returns true on success, false on error */
                     97: static int             ftp_getresp(ftpbuf_t *ftp);
                     98: 
                     99: /* sets the ftp transfer type */
                    100: static int             ftp_type(ftpbuf_t *ftp, ftptype_t type);
                    101: 
                    102: /* opens up a data stream */
                    103: static databuf_t*      ftp_getdata(ftpbuf_t *ftp TSRMLS_DC);
                    104: 
                    105: /* accepts the data connection, returns updated data buffer */
                    106: static databuf_t*      data_accept(databuf_t *data, ftpbuf_t *ftp TSRMLS_DC);
                    107: 
                    108: /* closes the data connection, returns NULL */
                    109: static databuf_t*      data_close(ftpbuf_t *ftp, databuf_t *data);
                    110: 
                    111: /* generic file lister */
                    112: static char**          ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC);
                    113: 
                    114: /* IP and port conversion box */
                    115: union ipbox {
                    116:        struct in_addr  ia[2];
                    117:        unsigned short  s[4];
                    118:        unsigned char   c[8];
                    119: };
                    120: 
                    121: /* {{{ ftp_open
                    122:  */
                    123: ftpbuf_t*
                    124: ftp_open(const char *host, short port, long timeout_sec TSRMLS_DC)
                    125: {
                    126:        ftpbuf_t                *ftp;
                    127:        socklen_t                size;
                    128:        struct timeval tv;
                    129: 
                    130: 
                    131:        /* alloc the ftp structure */
                    132:        ftp = ecalloc(1, sizeof(*ftp));
                    133: 
                    134:        tv.tv_sec = timeout_sec;
                    135:        tv.tv_usec = 0;
                    136: 
                    137:        ftp->fd = php_network_connect_socket_to_host(host,
                    138:                        (unsigned short) (port ? port : 21), SOCK_STREAM,
                    139:                        0, &tv, NULL, NULL, NULL, 0 TSRMLS_CC);
                    140:        if (ftp->fd == -1) {
                    141:                goto bail;
                    142:        }
                    143: 
                    144:        /* Default Settings */
                    145:        ftp->timeout_sec = timeout_sec;
                    146:        ftp->nb = 0;
                    147: 
                    148:        size = sizeof(ftp->localaddr);
                    149:        memset(&ftp->localaddr, 0, size);
                    150:        if (getsockname(ftp->fd, (struct sockaddr*) &ftp->localaddr, &size) != 0) {
                    151:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "getsockname failed: %s (%d)", strerror(errno), errno);
                    152:                goto bail;
                    153:        }
                    154: 
                    155:        if (!ftp_getresp(ftp) || ftp->resp != 220) {
                    156:                goto bail;
                    157:        }
                    158: 
                    159:        return ftp;
                    160: 
                    161: bail:
                    162:        if (ftp->fd != -1) {
                    163:                closesocket(ftp->fd);
                    164:        }
                    165:        efree(ftp);
                    166:        return NULL;
                    167: }
                    168: /* }}} */
                    169: 
                    170: /* {{{ ftp_close
                    171:  */
                    172: ftpbuf_t*
                    173: ftp_close(ftpbuf_t *ftp)
                    174: {
                    175:        if (ftp == NULL) {
                    176:                return NULL;
                    177:        }
                    178:        if (ftp->data) {
                    179:                data_close(ftp, ftp->data);
                    180:        }
                    181:        if (ftp->fd != -1) {
                    182: #if HAVE_OPENSSL_EXT
                    183:                if (ftp->ssl_active) {
                    184:                        SSL_shutdown(ftp->ssl_handle);
                    185:                }
                    186: #endif         
                    187:                closesocket(ftp->fd);
                    188:        }       
                    189:        ftp_gc(ftp);
                    190:        efree(ftp);
                    191:        return NULL;
                    192: }
                    193: /* }}} */
                    194: 
                    195: /* {{{ ftp_gc
                    196:  */
                    197: void
                    198: ftp_gc(ftpbuf_t *ftp)
                    199: {
                    200:        if (ftp == NULL) {
                    201:                return;
                    202:        }
                    203:        if (ftp->pwd) {
                    204:                efree(ftp->pwd);
                    205:                ftp->pwd = NULL;
                    206:        }
                    207:        if (ftp->syst) {
                    208:                efree(ftp->syst);
                    209:                ftp->syst = NULL;
                    210:        }
                    211: }
                    212: /* }}} */
                    213: 
                    214: /* {{{ ftp_quit
                    215:  */
                    216: int
                    217: ftp_quit(ftpbuf_t *ftp)
                    218: {
                    219:        if (ftp == NULL) {
                    220:                return 0;
                    221:        }
                    222: 
                    223:        if (!ftp_putcmd(ftp, "QUIT", NULL)) {
                    224:                return 0;
                    225:        }
                    226:        if (!ftp_getresp(ftp) || ftp->resp != 221) {
                    227:                return 0;
                    228:        }
                    229: 
                    230:        if (ftp->pwd) {
                    231:                efree(ftp->pwd);
                    232:                ftp->pwd = NULL;
                    233:        }
                    234: 
                    235:        return 1;
                    236: }
                    237: /* }}} */
                    238: 
                    239: /* {{{ ftp_login
                    240:  */
                    241: int
                    242: ftp_login(ftpbuf_t *ftp, const char *user, const char *pass TSRMLS_DC)
                    243: {
                    244: #if HAVE_OPENSSL_EXT
                    245:        SSL_CTX *ctx = NULL;
                    246: #endif
                    247:        if (ftp == NULL) {
                    248:                return 0;
                    249:        }
                    250: 
                    251: #if HAVE_OPENSSL_EXT
                    252:        if (ftp->use_ssl && !ftp->ssl_active) {
                    253:                if (!ftp_putcmd(ftp, "AUTH", "TLS")) {
                    254:                        return 0;
                    255:                }
                    256:                if (!ftp_getresp(ftp)) {
                    257:                        return 0;
                    258:                }
                    259:                        
                    260:                if (ftp->resp != 234) {
                    261:                        if (!ftp_putcmd(ftp, "AUTH", "SSL")) {
                    262:                                return 0;
                    263:                        }
                    264:                        if (!ftp_getresp(ftp)) {
                    265:                                return 0;
                    266:                        }
                    267:                                
                    268:                        if (ftp->resp != 334) {
                    269:                                return 0;
                    270:                        } else {
                    271:                                ftp->old_ssl = 1;
                    272:                                ftp->use_ssl_for_data = 1;
                    273:                        }
                    274:                }
                    275:                
                    276:                ctx = SSL_CTX_new(SSLv23_client_method());
                    277:                if (ctx == NULL) {
                    278:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create the SSL context");
                    279:                        return 0;
                    280:                }
                    281: 
                    282:                SSL_CTX_set_options(ctx, SSL_OP_ALL);
                    283: 
                    284:                ftp->ssl_handle = SSL_new(ctx);
                    285:                if (ftp->ssl_handle == NULL) {
                    286:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create the SSL handle");
                    287:                        SSL_CTX_free(ctx);
                    288:                        return 0;
                    289:                }
                    290: 
                    291:                SSL_set_fd(ftp->ssl_handle, ftp->fd);
                    292: 
                    293:                if (SSL_connect(ftp->ssl_handle) <= 0) {
                    294:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS handshake failed");
                    295:                        SSL_shutdown(ftp->ssl_handle);
                    296:                        return 0;
                    297:                }
                    298: 
                    299:                ftp->ssl_active = 1;
                    300: 
                    301:                if (!ftp->old_ssl) {
                    302: 
                    303:                        /* set protection buffersize to zero */
                    304:                        if (!ftp_putcmd(ftp, "PBSZ", "0")) {
                    305:                                return 0;
                    306:                        }
                    307:                        if (!ftp_getresp(ftp)) {
                    308:                                return 0;
                    309:                        }
                    310: 
                    311:                        /* enable data conn encryption */
                    312:                        if (!ftp_putcmd(ftp, "PROT", "P")) {
                    313:                                return 0;
                    314:                        }
                    315:                        if (!ftp_getresp(ftp)) {
                    316:                                return 0;
                    317:                        }
                    318:                        
                    319:                        ftp->use_ssl_for_data = (ftp->resp >= 200 && ftp->resp <=299);          
                    320:                }
                    321:        }
                    322: #endif
                    323: 
                    324:        if (!ftp_putcmd(ftp, "USER", user)) {
                    325:                return 0;
                    326:        }
                    327:        if (!ftp_getresp(ftp)) {
                    328:                return 0;
                    329:        }
                    330:        if (ftp->resp == 230) {
                    331:                return 1;
                    332:        }
                    333:        if (ftp->resp != 331) {
                    334:                return 0;
                    335:        }
                    336:        if (!ftp_putcmd(ftp, "PASS", pass)) {
                    337:                return 0;
                    338:        }
                    339:        if (!ftp_getresp(ftp)) {
                    340:                return 0;
                    341:        }
                    342:        return (ftp->resp == 230);
                    343: }
                    344: /* }}} */
                    345: 
                    346: /* {{{ ftp_reinit
                    347:  */
                    348: int
                    349: ftp_reinit(ftpbuf_t *ftp)
                    350: {
                    351:        if (ftp == NULL) {
                    352:                return 0;
                    353:        }       
                    354: 
                    355:        ftp_gc(ftp);
                    356: 
                    357:        ftp->nb = 0;
                    358: 
                    359:        if (!ftp_putcmd(ftp, "REIN", NULL)) {
                    360:                return 0;
                    361:        }
                    362:        if (!ftp_getresp(ftp) || ftp->resp != 220) {
                    363:                return 0;
                    364:        }
                    365: 
                    366:        return 1;
                    367: }
                    368: /* }}} */
                    369: 
                    370: /* {{{ ftp_syst
                    371:  */
                    372: const char*
                    373: ftp_syst(ftpbuf_t *ftp)
                    374: {
                    375:        char *syst, *end;
                    376: 
                    377:        if (ftp == NULL) {
                    378:                return NULL;
                    379:        }
                    380: 
                    381:        /* default to cached value */
                    382:        if (ftp->syst) {
                    383:                return ftp->syst;
                    384:        }
                    385:        if (!ftp_putcmd(ftp, "SYST", NULL)) {
                    386:                return NULL;
                    387:        }
                    388:        if (!ftp_getresp(ftp) || ftp->resp != 215) { 
                    389:                return NULL;
                    390:        }
                    391:        syst = ftp->inbuf;
                    392:        while (*syst == ' ') {
                    393:                syst++;
                    394:        }
                    395:        if ((end = strchr(syst, ' '))) {
                    396:                *end = 0;
                    397:        }
                    398:        ftp->syst = estrdup(syst);
                    399:        if (end) {
                    400:                *end = ' ';
                    401:        }
                    402:        return ftp->syst;
                    403: }
                    404: /* }}} */
                    405: 
                    406: /* {{{ ftp_pwd
                    407:  */
                    408: const char*
                    409: ftp_pwd(ftpbuf_t *ftp)
                    410: {
                    411:        char *pwd, *end;
                    412: 
                    413:        if (ftp == NULL) {
                    414:                return NULL;
                    415:        }
                    416: 
                    417:        /* default to cached value */
                    418:        if (ftp->pwd) {
                    419:                return ftp->pwd;
                    420:        }
                    421:        if (!ftp_putcmd(ftp, "PWD", NULL)) {
                    422:                return NULL;
                    423:        }
                    424:        if (!ftp_getresp(ftp) || ftp->resp != 257) { 
                    425:                return NULL;
                    426:        }
                    427:        /* copy out the pwd from response */
                    428:        if ((pwd = strchr(ftp->inbuf, '"')) == NULL) { 
                    429:                return NULL;
                    430:        }
                    431:        if ((end = strrchr(++pwd, '"')) == NULL) { 
                    432:                return NULL;
                    433:        }
                    434:        ftp->pwd = estrndup(pwd, end - pwd);
                    435: 
                    436:        return ftp->pwd;
                    437: }
                    438: /* }}} */
                    439: 
                    440: /* {{{ ftp_exec
                    441:  */
                    442: int
                    443: ftp_exec(ftpbuf_t *ftp, const char *cmd)
                    444: {
                    445:        if (ftp == NULL) {
                    446:                return 0;
                    447:        }
                    448:        if (!ftp_putcmd(ftp, "SITE EXEC", cmd)) {
                    449:                return 0;
                    450:        }
                    451:        if (!ftp_getresp(ftp) || ftp->resp != 200) {
                    452:                return 0;
                    453:        }
                    454: 
                    455:        return 1;
                    456: }
                    457: /* }}} */
                    458: 
                    459: /* {{{ ftp_raw
                    460:  */
                    461: void
                    462: ftp_raw(ftpbuf_t *ftp, const char *cmd, zval *return_value)
                    463: {
                    464:        if (ftp == NULL || cmd == NULL) {
                    465:                RETURN_NULL();
                    466:        }
                    467:        if (!ftp_putcmd(ftp, cmd, NULL)) {
                    468:                RETURN_NULL();
                    469:        }
                    470:        array_init(return_value);
                    471:        while (ftp_readline(ftp)) {
                    472:                add_next_index_string(return_value, ftp->inbuf, 1);
                    473:                if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
                    474:                        return;
                    475:                }
                    476:        }
                    477: }
                    478: /* }}} */
                    479: 
                    480: /* {{{ ftp_chdir
                    481:  */
                    482: int
                    483: ftp_chdir(ftpbuf_t *ftp, const char *dir)
                    484: {
                    485:        if (ftp == NULL) {
                    486:                return 0;
                    487:        }
                    488: 
                    489:        if (ftp->pwd) {
                    490:                efree(ftp->pwd);
                    491:                ftp->pwd = NULL;
                    492:        }
                    493: 
                    494:        if (!ftp_putcmd(ftp, "CWD", dir)) {
                    495:                return 0;
                    496:        }
                    497:        if (!ftp_getresp(ftp) || ftp->resp != 250) {
                    498:                return 0;
                    499:        }
                    500:        return 1;
                    501: }
                    502: /* }}} */
                    503: 
                    504: /* {{{ ftp_cdup
                    505:  */
                    506: int
                    507: ftp_cdup(ftpbuf_t *ftp)
                    508: {
                    509:        if (ftp == NULL) {
                    510:                return 0;
                    511:        }
                    512: 
                    513:        if (ftp->pwd) {
                    514:                efree(ftp->pwd);
                    515:                ftp->pwd = NULL;
                    516:        }
                    517: 
                    518:        if (!ftp_putcmd(ftp, "CDUP", NULL)) {
                    519:                return 0;
                    520:        }
                    521:        if (!ftp_getresp(ftp) || ftp->resp != 250) {
                    522:                return 0;
                    523:        }
                    524:        return 1;
                    525: }
                    526: /* }}} */
                    527: 
                    528: /* {{{ ftp_mkdir
                    529:  */
                    530: char*
                    531: ftp_mkdir(ftpbuf_t *ftp, const char *dir)
                    532: {
                    533:        char *mkd, *end;
                    534: 
                    535:        if (ftp == NULL) {
                    536:                return NULL;
                    537:        }
                    538:        if (!ftp_putcmd(ftp, "MKD", dir)) {
                    539:                return NULL;
                    540:        }
                    541:        if (!ftp_getresp(ftp) || ftp->resp != 257) {
                    542:                return NULL;
                    543:        }
                    544:        /* copy out the dir from response */
                    545:        if ((mkd = strchr(ftp->inbuf, '"')) == NULL) {
                    546:                mkd = estrdup(dir);
                    547:                return mkd;
                    548:        }
                    549:        if ((end = strrchr(++mkd, '"')) == NULL) {
                    550:                return NULL;
                    551:        }
                    552:        *end = 0;
                    553:        mkd = estrdup(mkd);
                    554:        *end = '"';
                    555: 
                    556:        return mkd;
                    557: }
                    558: /* }}} */
                    559: 
                    560: /* {{{ ftp_rmdir
                    561:  */
                    562: int
                    563: ftp_rmdir(ftpbuf_t *ftp, const char *dir)
                    564: {
                    565:        if (ftp == NULL) {
                    566:                return 0;
                    567:        }
                    568:        if (!ftp_putcmd(ftp, "RMD", dir)) {
                    569:                return 0;
                    570:        }
                    571:        if (!ftp_getresp(ftp) || ftp->resp != 250) {
                    572:                return 0;
                    573:        }
                    574:        return 1;
                    575: }
                    576: /* }}} */
                    577: 
                    578: /* {{{ ftp_chmod
                    579:  */
                    580: int
                    581: ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const int filename_len)
                    582: {
                    583:        char *buffer;
                    584: 
                    585:        if (ftp == NULL || filename_len <= 0) {
                    586:                return 0;
                    587:        }
                    588: 
                    589:        spprintf(&buffer, 0, "CHMOD %o %s", mode, filename);
                    590: 
                    591:        if (!ftp_putcmd(ftp, "SITE", buffer)) {
                    592:                efree(buffer);
                    593:                return 0;
                    594:        }
                    595: 
                    596:        efree(buffer);
                    597: 
                    598:        if (!ftp_getresp(ftp) || ftp->resp != 200) {
                    599:                return 0;
                    600:        }
                    601:        
                    602:        return 1;
                    603: }
                    604: /* }}} */
                    605: 
                    606: /* {{{ ftp_alloc
                    607:  */
                    608: int
                    609: ftp_alloc(ftpbuf_t *ftp, const int size, char **response)
                    610: {
                    611:        char buffer[64];
                    612: 
                    613:        if (ftp == NULL || size <= 0) {
                    614:                return 0;
                    615:        }
                    616: 
                    617:        snprintf(buffer, sizeof(buffer) - 1, "%d", size);
                    618: 
                    619:        if (!ftp_putcmd(ftp, "ALLO", buffer)) {
                    620:                return 0;
                    621:        }
                    622: 
                    623:        if (!ftp_getresp(ftp)) {
                    624:                return 0;
                    625:        }
                    626: 
                    627:        if (response && ftp->inbuf) {
                    628:                *response = estrdup(ftp->inbuf);
                    629:        }
                    630: 
                    631:        if (ftp->resp < 200 || ftp->resp >= 300) {
                    632:                return 0;
                    633:        }
                    634: 
                    635:        return 1;       
                    636: }
                    637: /* }}} */
                    638: 
                    639: /* {{{ ftp_nlist
                    640:  */
                    641: char**
                    642: ftp_nlist(ftpbuf_t *ftp, const char *path TSRMLS_DC)
                    643: {
                    644:        return ftp_genlist(ftp, "NLST", path TSRMLS_CC);
                    645: }
                    646: /* }}} */
                    647: 
                    648: /* {{{ ftp_list
                    649:  */
                    650: char**
                    651: ftp_list(ftpbuf_t *ftp, const char *path, int recursive TSRMLS_DC)
                    652: {
                    653:        return ftp_genlist(ftp, ((recursive) ? "LIST -R" : "LIST"), path TSRMLS_CC);
                    654: }
                    655: /* }}} */
                    656: 
                    657: /* {{{ ftp_type
                    658:  */
                    659: int
                    660: ftp_type(ftpbuf_t *ftp, ftptype_t type)
                    661: {
                    662:        char typechar[2] = "?";
                    663: 
                    664:        if (ftp == NULL) {
                    665:                return 0;
                    666:        }
                    667:        if (type == ftp->type) { 
                    668:                return 1;
                    669:        }
                    670:        if (type == FTPTYPE_ASCII) {
                    671:                typechar[0] = 'A';
                    672:        } else if (type == FTPTYPE_IMAGE) {
                    673:                typechar[0] = 'I';
                    674:        } else {
                    675:                return 0;
                    676:        }
                    677:        if (!ftp_putcmd(ftp, "TYPE", typechar)) {
                    678:                return 0;
                    679:        }
                    680:        if (!ftp_getresp(ftp) || ftp->resp != 200) {
                    681:                return 0;
                    682:        }
                    683:        ftp->type = type;
                    684: 
                    685:        return 1;
                    686: }
                    687: /* }}} */
                    688: 
                    689: /* {{{ ftp_pasv
                    690:  */
                    691: int
                    692: ftp_pasv(ftpbuf_t *ftp, int pasv)
                    693: {
                    694:        char                    *ptr;
                    695:        union ipbox             ipbox;
                    696:        unsigned long           b[6];
                    697:        socklen_t                       n;
                    698:        struct sockaddr *sa;
                    699:        struct sockaddr_in *sin;
                    700: 
                    701:        if (ftp == NULL) {
                    702:                return 0;
                    703:        }
                    704:        if (pasv && ftp->pasv == 2) {
                    705:                return 1;
                    706:        }
                    707:        ftp->pasv = 0;
                    708:        if (!pasv) {
                    709:                return 1;
                    710:        }
                    711:        n = sizeof(ftp->pasvaddr);
                    712:        memset(&ftp->pasvaddr, 0, n);
                    713:        sa = (struct sockaddr *) &ftp->pasvaddr;
                    714: 
                    715: #if HAVE_IPV6
                    716:        if (getpeername(ftp->fd, sa, &n) < 0) {
                    717:                return 0;
                    718:        }
                    719:        if (sa->sa_family == AF_INET6) {
                    720:                struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
                    721:                char *endptr, delimiter;
                    722: 
                    723:                /* try EPSV first */
                    724:                if (!ftp_putcmd(ftp, "EPSV", NULL)) {
                    725:                        return 0;
                    726:                }
                    727:                if (!ftp_getresp(ftp)) {
                    728:                        return 0;
                    729:                }
                    730:                if (ftp->resp == 229) {
                    731:                        /* parse out the port */
                    732:                        for (ptr = ftp->inbuf; *ptr && *ptr != '('; ptr++);
                    733:                        if (!*ptr) {
                    734:                                return 0;
                    735:                        }
                    736:                        delimiter = *++ptr;
                    737:                        for (n = 0; *ptr && n < 3; ptr++) {
                    738:                                if (*ptr == delimiter) {
                    739:                                        n++;
                    740:                                }
                    741:                        }
                    742: 
                    743:                        sin6->sin6_port = htons((unsigned short) strtoul(ptr, &endptr, 10));
                    744:                        if (ptr == endptr || *endptr != delimiter) {
                    745:                                return 0;
                    746:                        }
                    747:                        ftp->pasv = 2;
                    748:                        return 1;
                    749:                }
                    750:        }
                    751: 
                    752:        /* fall back to PASV */
                    753: #endif
                    754: 
                    755:        if (!ftp_putcmd(ftp, "PASV", NULL)) {
                    756:                return 0;
                    757:        }
                    758:        if (!ftp_getresp(ftp) || ftp->resp != 227) { 
                    759:                return 0;
                    760:        }
                    761:        /* parse out the IP and port */
                    762:        for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
                    763:        n = sscanf(ptr, "%lu,%lu,%lu,%lu,%lu,%lu", &b[0], &b[1], &b[2], &b[3], &b[4], &b[5]);
                    764:        if (n != 6) {
                    765:                return 0;
                    766:        }
                    767:        for (n = 0; n < 6; n++) {
                    768:                ipbox.c[n] = (unsigned char) b[n];
                    769:        }
                    770:        sin = (struct sockaddr_in *) sa;
                    771:        sin->sin_family = AF_INET;
                    772:        sin->sin_addr = ipbox.ia[0];
                    773:        sin->sin_port = ipbox.s[2];
                    774: 
                    775:        ftp->pasv = 2;
                    776: 
                    777:        return 1;
                    778: }
                    779: /* }}} */
                    780: 
                    781: /* {{{ ftp_get
                    782:  */
                    783: int
                    784: ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, int resumepos TSRMLS_DC)
                    785: {
                    786:        databuf_t               *data = NULL;
                    787:        int                     lastch;
                    788:        size_t                  rcvd;
                    789:        char                    arg[11];
                    790: 
                    791:        if (ftp == NULL) {
                    792:                return 0;
                    793:        }
                    794:        if (!ftp_type(ftp, type)) {
                    795:                goto bail;
                    796:        }
                    797: 
                    798:        if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
                    799:                goto bail;
                    800:        }
                    801:        
                    802:        ftp->data = data;
                    803: 
                    804:        if (resumepos > 0) {
                    805:                if (resumepos > 2147483647) {
                    806:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP cannot handle files greater than 2147483647 bytes.");
                    807:                        goto bail;
                    808:                }
                    809:                snprintf(arg, sizeof(arg), "%u", resumepos);
                    810:                if (!ftp_putcmd(ftp, "REST", arg)) {
                    811:                        goto bail;
                    812:                }
                    813:                if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
                    814:                        goto bail;
                    815:                }
                    816:        }
                    817: 
                    818:        if (!ftp_putcmd(ftp, "RETR", path)) {
                    819:                goto bail;
                    820:        }
                    821:        if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
                    822:                goto bail;
                    823:        }
                    824: 
                    825:        if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
                    826:                goto bail;
                    827:        }
                    828: 
                    829:        lastch = 0;
                    830:        while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
                    831:                if (rcvd == -1) {
                    832:                        goto bail;
                    833:                }
                    834: 
                    835:                if (type == FTPTYPE_ASCII) {
                    836: #ifndef PHP_WIN32
                    837:                        char *s;
                    838: #endif
                    839:                        char *ptr = data->buf;
                    840:                        char *e = ptr + rcvd;
                    841:                        /* logic depends on the OS EOL
                    842:                         * Win32 -> \r\n
                    843:                         * Everything Else \n
                    844:                         */
                    845: #ifdef PHP_WIN32
                    846:                        php_stream_write(outstream, ptr, (e - ptr));
                    847:                        ptr = e;
                    848: #else
                    849:                        while (e > ptr && (s = memchr(ptr, '\r', (e - ptr)))) {
                    850:                                php_stream_write(outstream, ptr, (s - ptr));
                    851:                                if (*(s + 1) == '\n') {
                    852:                                        s++;
                    853:                                        php_stream_putc(outstream, '\n');
                    854:                                }
                    855:                                ptr = s + 1;
                    856:                        }
                    857: #endif
                    858:                        if (ptr < e) {
                    859:                                php_stream_write(outstream, ptr, (e - ptr));
                    860:                        }
                    861:                } else if (rcvd != php_stream_write(outstream, data->buf, rcvd)) {
                    862:                        goto bail;
                    863:                }
                    864:        }
                    865: 
                    866:        ftp->data = data = data_close(ftp, data);
                    867: 
                    868:        if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
                    869:                goto bail;
                    870:        }
                    871: 
                    872:        return 1;
                    873: bail:
                    874:        ftp->data = data_close(ftp, data);
                    875:        return 0;
                    876: }
                    877: /* }}} */
                    878: 
                    879: /* {{{ ftp_put
                    880:  */
                    881: int
                    882: ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, int startpos TSRMLS_DC)
                    883: {
                    884:        databuf_t               *data = NULL;
                    885:        int                     size;
                    886:        char                    *ptr;
                    887:        int                     ch;
                    888:        char                    arg[11];
                    889: 
                    890:        if (ftp == NULL) {
                    891:                return 0;
                    892:        }
                    893:        if (!ftp_type(ftp, type)) {
                    894:                goto bail;
                    895:        }
                    896:        if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
                    897:                goto bail;
                    898:        }
                    899:        ftp->data = data;       
                    900: 
                    901:        if (startpos > 0) {
                    902:                if (startpos > 2147483647) {
                    903:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP cannot handle files with a size greater than 2147483647 bytes.");
                    904:                        goto bail;
                    905:                }
                    906:                snprintf(arg, sizeof(arg), "%u", startpos);
                    907:                if (!ftp_putcmd(ftp, "REST", arg)) {
                    908:                        goto bail;
                    909:                }
                    910:                if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
                    911:                        goto bail;
                    912:                }
                    913:        }
                    914: 
                    915:        if (!ftp_putcmd(ftp, "STOR", path)) {
                    916:                goto bail;
                    917:        }
                    918:        if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
                    919:                goto bail;
                    920:        }
                    921:        if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
                    922:                goto bail;
                    923:        }
                    924: 
                    925:        size = 0;
                    926:        ptr = data->buf;
                    927:        while (!php_stream_eof(instream) && (ch = php_stream_getc(instream))!=EOF) {
                    928:                /* flush if necessary */
                    929:                if (FTP_BUFSIZE - size < 2) {
                    930:                        if (my_send(ftp, data->fd, data->buf, size) != size) {
                    931:                                goto bail;
                    932:                        }
                    933:                        ptr = data->buf;
                    934:                        size = 0;
                    935:                }
                    936: 
                    937:                if (ch == '\n' && type == FTPTYPE_ASCII) {
                    938:                        *ptr++ = '\r';
                    939:                        size++;
                    940:                }
                    941: 
                    942:                *ptr++ = ch;
                    943:                size++;
                    944:        }
                    945: 
                    946:        if (size && my_send(ftp, data->fd, data->buf, size) != size) {
                    947:                goto bail;
                    948:        }
                    949:        ftp->data = data = data_close(ftp, data);
                    950: 
                    951:        if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) {
                    952:                goto bail;
                    953:        }
                    954:        return 1;
                    955: bail:
                    956:        ftp->data = data_close(ftp, data);
                    957:        return 0;
                    958: }
                    959: /* }}} */
                    960: 
                    961: /* {{{ ftp_size
                    962:  */
                    963: int
                    964: ftp_size(ftpbuf_t *ftp, const char *path)
                    965: {
                    966:        if (ftp == NULL) {
                    967:                return -1;
                    968:        }
                    969:        if (!ftp_type(ftp, FTPTYPE_IMAGE)) {
                    970:                return -1;
                    971:        }
                    972:        if (!ftp_putcmd(ftp, "SIZE", path)) {
                    973:                return -1;
                    974:        }
                    975:        if (!ftp_getresp(ftp) || ftp->resp != 213) {
                    976:                return -1;
                    977:        }
                    978:        return atoi(ftp->inbuf);
                    979: }
                    980: /* }}} */
                    981: 
                    982: /* {{{ ftp_mdtm
                    983:  */
                    984: time_t
                    985: ftp_mdtm(ftpbuf_t *ftp, const char *path)
                    986: {
                    987:        time_t          stamp;
                    988:        struct tm       *gmt, tmbuf;
                    989:        struct tm       tm;
                    990:        char            *ptr;
                    991:        int             n;
                    992: 
                    993:        if (ftp == NULL) {
                    994:                return -1;
                    995:        }
                    996:        if (!ftp_putcmd(ftp, "MDTM", path)) {
                    997:                return -1;
                    998:        }
                    999:        if (!ftp_getresp(ftp) || ftp->resp != 213) {
                   1000:                return -1;
                   1001:        }
                   1002:        /* parse out the timestamp */
                   1003:        for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
                   1004:        n = sscanf(ptr, "%4u%2u%2u%2u%2u%2u", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
                   1005:        if (n != 6) {
                   1006:                return -1;
                   1007:        }
                   1008:        tm.tm_year -= 1900;
                   1009:        tm.tm_mon--;
                   1010:        tm.tm_isdst = -1;
                   1011: 
                   1012:        /* figure out the GMT offset */
                   1013:        stamp = time(NULL);
                   1014:        gmt = php_gmtime_r(&stamp, &tmbuf);
                   1015:        if (!gmt) {
                   1016:                return -1;
                   1017:        }
                   1018:        gmt->tm_isdst = -1;
                   1019: 
                   1020:        /* apply the GMT offset */
                   1021:        tm.tm_sec += stamp - mktime(gmt);
                   1022:        tm.tm_isdst = gmt->tm_isdst;
                   1023: 
                   1024:        stamp = mktime(&tm);
                   1025: 
                   1026:        return stamp;
                   1027: }
                   1028: /* }}} */
                   1029: 
                   1030: /* {{{ ftp_delete
                   1031:  */
                   1032: int
                   1033: ftp_delete(ftpbuf_t *ftp, const char *path)
                   1034: {
                   1035:        if (ftp == NULL) {
                   1036:                return 0;
                   1037:        }
                   1038:        if (!ftp_putcmd(ftp, "DELE", path)) {
                   1039:                return 0;
                   1040:        }
                   1041:        if (!ftp_getresp(ftp) || ftp->resp != 250) {
                   1042:                return 0;
                   1043:        }
                   1044: 
                   1045:        return 1;
                   1046: }
                   1047: /* }}} */
                   1048: 
                   1049: /* {{{ ftp_rename
                   1050:  */
                   1051: int
                   1052: ftp_rename(ftpbuf_t *ftp, const char *src, const char *dest)
                   1053: {
                   1054:        if (ftp == NULL) {
                   1055:                return 0;
                   1056:        }
                   1057:        if (!ftp_putcmd(ftp, "RNFR", src)) {
                   1058:                return 0;
                   1059:        }
                   1060:        if (!ftp_getresp(ftp) || ftp->resp != 350) {
                   1061:                return 0;
                   1062:        }
                   1063:        if (!ftp_putcmd(ftp, "RNTO", dest)) {
                   1064:                return 0;
                   1065:        }
                   1066:        if (!ftp_getresp(ftp) || ftp->resp != 250) {
                   1067:                return 0;
                   1068:        }
                   1069:        return 1;
                   1070: }
                   1071: /* }}} */
                   1072: 
                   1073: /* {{{ ftp_site
                   1074:  */
                   1075: int
                   1076: ftp_site(ftpbuf_t *ftp, const char *cmd)
                   1077: {
                   1078:        if (ftp == NULL) {
                   1079:                return 0;
                   1080:        }
                   1081:        if (!ftp_putcmd(ftp, "SITE", cmd)) {
                   1082:                return 0;
                   1083:        }
                   1084:        if (!ftp_getresp(ftp) || ftp->resp < 200 || ftp->resp >= 300) {
                   1085:                return 0;
                   1086:        }
                   1087: 
                   1088:        return 1;
                   1089: }
                   1090: /* }}} */
                   1091: 
                   1092: /* static functions */
                   1093: 
                   1094: /* {{{ ftp_putcmd
                   1095:  */
                   1096: int
                   1097: ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const char *args)
                   1098: {
                   1099:        int             size;
                   1100:        char            *data;
                   1101: 
                   1102:        if (strpbrk(cmd, "\r\n")) {
                   1103:                return 0;
                   1104:        } 
                   1105:        /* build the output buffer */
                   1106:        if (args && args[0]) {
                   1107:                /* "cmd args\r\n\0" */
                   1108:                if (strlen(cmd) + strlen(args) + 4 > FTP_BUFSIZE) {
                   1109:                        return 0;
                   1110:                }
                   1111:                if (strpbrk(args, "\r\n")) {
                   1112:                        return 0;
                   1113:                }
                   1114:                size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s %s\r\n", cmd, args);
                   1115:        } else {
                   1116:                /* "cmd\r\n\0" */
                   1117:                if (strlen(cmd) + 3 > FTP_BUFSIZE) {
                   1118:                        return 0;
                   1119:                }
                   1120:                size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s\r\n", cmd);
                   1121:        }
                   1122: 
                   1123:        data = ftp->outbuf;
                   1124: 
                   1125:        /* Clear the extra-lines buffer */
                   1126:        ftp->extra = NULL;
                   1127: 
                   1128:        if (my_send(ftp, ftp->fd, data, size) != size) {
                   1129:                return 0;
                   1130:        }
                   1131:        return 1;
                   1132: }
                   1133: /* }}} */
                   1134: 
                   1135: /* {{{ ftp_readline
                   1136:  */
                   1137: int
                   1138: ftp_readline(ftpbuf_t *ftp)
                   1139: {
                   1140:        int             size, rcvd;
                   1141:        char            *data, *eol;
                   1142: 
                   1143:        /* shift the extra to the front */
                   1144:        size = FTP_BUFSIZE;
                   1145:        rcvd = 0;
                   1146:        if (ftp->extra) {
                   1147:                memmove(ftp->inbuf, ftp->extra, ftp->extralen);
                   1148:                rcvd = ftp->extralen;
                   1149:        }
                   1150: 
                   1151:        data = ftp->inbuf;
                   1152: 
                   1153:        do {
                   1154:                size -= rcvd;
                   1155:                for (eol = data; rcvd; rcvd--, eol++) {
                   1156:                        if (*eol == '\r') {
                   1157:                                *eol = 0;
                   1158:                                ftp->extra = eol + 1;
                   1159:                                if (rcvd > 1 && *(eol + 1) == '\n') {
                   1160:                                        ftp->extra++;
                   1161:                                        rcvd--;
                   1162:                                }
                   1163:                                if ((ftp->extralen = --rcvd) == 0) {
                   1164:                                        ftp->extra = NULL;
                   1165:                                }
                   1166:                                return 1;
                   1167:                        } else if (*eol == '\n') {
                   1168:                                *eol = 0;
                   1169:                                ftp->extra = eol + 1;
                   1170:                                if ((ftp->extralen = --rcvd) == 0) {
                   1171:                                        ftp->extra = NULL;
                   1172:                                }
                   1173:                                return 1;
                   1174:                        }
                   1175:                }
                   1176: 
                   1177:                data = eol;
                   1178:                if ((rcvd = my_recv(ftp, ftp->fd, data, size)) < 1) {
                   1179:                        return 0;
                   1180:                }
                   1181:        } while (size);
                   1182: 
                   1183:        return 0;
                   1184: }
                   1185: /* }}} */
                   1186: 
                   1187: /* {{{ ftp_getresp
                   1188:  */
                   1189: int
                   1190: ftp_getresp(ftpbuf_t *ftp)
                   1191: {
                   1192:        char *buf;
                   1193: 
                   1194:        if (ftp == NULL) {
                   1195:                return 0;
                   1196:        }
                   1197:        buf = ftp->inbuf;
                   1198:        ftp->resp = 0;
                   1199: 
                   1200:        while (1) {
                   1201: 
                   1202:                if (!ftp_readline(ftp)) {
                   1203:                        return 0;
                   1204:                }
                   1205: 
                   1206:                /* Break out when the end-tag is found */
                   1207:                if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
                   1208:                        break;
                   1209:                }
                   1210:        }
                   1211: 
                   1212:        /* translate the tag */
                   1213:        if (!isdigit(ftp->inbuf[0]) || !isdigit(ftp->inbuf[1]) || !isdigit(ftp->inbuf[2])) {
                   1214:                return 0;
                   1215:        }
                   1216: 
                   1217:        ftp->resp = 100 * (ftp->inbuf[0] - '0') + 10 * (ftp->inbuf[1] - '0') + (ftp->inbuf[2] - '0');
                   1218: 
                   1219:        memmove(ftp->inbuf, ftp->inbuf + 4, FTP_BUFSIZE - 4);
                   1220: 
                   1221:        if (ftp->extra) {
                   1222:                ftp->extra -= 4;
                   1223:        }
                   1224:        return 1;
                   1225: }
                   1226: /* }}} */
                   1227: 
                   1228: /* {{{ my_send
                   1229:  */
                   1230: int
                   1231: my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
                   1232: {
                   1233:        int             n, size, sent;
                   1234: 
                   1235:        size = len;
                   1236:        while (size) {
                   1237:                n = php_pollfd_for_ms(s, POLLOUT, ftp->timeout_sec * 1000);
                   1238: 
                   1239:                if (n < 1) {
                   1240: 
                   1241: #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
                   1242:                        if (n == 0) {
                   1243:                                errno = ETIMEDOUT;
                   1244:                        }
                   1245: #endif
                   1246:                        return -1;
                   1247:                }
                   1248: 
                   1249: #if HAVE_OPENSSL_EXT
                   1250:                if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
                   1251:                        sent = SSL_write(ftp->ssl_handle, buf, size);
                   1252:                } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {    
                   1253:                        sent = SSL_write(ftp->data->ssl_handle, buf, size);
                   1254:                } else {
                   1255: #endif
                   1256:                        sent = send(s, buf, size, 0);
                   1257: #if HAVE_OPENSSL_EXT
                   1258:                }
                   1259: #endif
                   1260:                if (sent == -1) {
                   1261:                        return -1;
                   1262:                }
                   1263: 
                   1264:                buf = (char*) buf + sent;
                   1265:                size -= sent;
                   1266:        }
                   1267: 
                   1268:        return len;
                   1269: }
                   1270: /* }}} */
                   1271: 
                   1272: /* {{{ my_recv
                   1273:  */
                   1274: int
                   1275: my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
                   1276: {
                   1277:        int             n, nr_bytes;
                   1278: 
                   1279:        n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
                   1280:        if (n < 1) {
                   1281: #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
                   1282:                if (n == 0) {
                   1283:                        errno = ETIMEDOUT;
                   1284:                }
                   1285: #endif
                   1286:                return -1;
                   1287:        }
                   1288: 
                   1289: #if HAVE_OPENSSL_EXT
                   1290:        if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
                   1291:                nr_bytes = SSL_read(ftp->ssl_handle, buf, len);
                   1292:        } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {    
                   1293:                nr_bytes = SSL_read(ftp->data->ssl_handle, buf, len);
                   1294:        } else {
                   1295: #endif
                   1296:                nr_bytes = recv(s, buf, len, 0);
                   1297: #if HAVE_OPENSSL_EXT
                   1298:        }
                   1299: #endif 
                   1300:        return (nr_bytes);
                   1301: }
                   1302: /* }}} */
                   1303: 
                   1304: /* {{{ data_available
                   1305:  */
                   1306: int
                   1307: data_available(ftpbuf_t *ftp, php_socket_t s)
                   1308: {
                   1309:        int             n;
                   1310: 
                   1311:        n = php_pollfd_for_ms(s, PHP_POLLREADABLE, 1000);
                   1312:        if (n < 1) {
                   1313: #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
                   1314:                if (n == 0) {
                   1315:                        errno = ETIMEDOUT;
                   1316:                }
                   1317: #endif
                   1318:                return 0;
                   1319:        }
                   1320: 
                   1321:        return 1;
                   1322: }
                   1323: /* }}} */
                   1324: /* {{{ data_writeable
                   1325:  */
                   1326: int
                   1327: data_writeable(ftpbuf_t *ftp, php_socket_t s)
                   1328: {
                   1329:        int             n;
                   1330: 
                   1331:        n = php_pollfd_for_ms(s, POLLOUT, 1000);
                   1332:        if (n < 1) {
                   1333: #ifndef PHP_WIN32
                   1334:                if (n == 0) {
                   1335:                        errno = ETIMEDOUT;
                   1336:                }
                   1337: #endif
                   1338:                return 0;
                   1339:        }
                   1340: 
                   1341:        return 1;
                   1342: }
                   1343: /* }}} */
                   1344: 
                   1345: /* {{{ my_accept
                   1346:  */
                   1347: int
                   1348: my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen)
                   1349: {
                   1350:        int             n;
                   1351: 
                   1352:        n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
                   1353:        if (n < 1) {
                   1354: #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
                   1355:                if (n == 0) {
                   1356:                        errno = ETIMEDOUT;
                   1357:                }
                   1358: #endif
                   1359:                return -1;
                   1360:        }
                   1361: 
                   1362:        return accept(s, addr, addrlen);
                   1363: }
                   1364: /* }}} */
                   1365: 
                   1366: /* {{{ ftp_getdata
                   1367:  */
                   1368: databuf_t*
                   1369: ftp_getdata(ftpbuf_t *ftp TSRMLS_DC)
                   1370: {
                   1371:        int                     fd = -1;
                   1372:        databuf_t               *data;
                   1373:        php_sockaddr_storage addr;
                   1374:        struct sockaddr *sa;
                   1375:        socklen_t               size;
                   1376:        union ipbox             ipbox;
                   1377:        char                    arg[sizeof("255, 255, 255, 255, 255, 255")];
                   1378:        struct timeval  tv;
                   1379: 
                   1380: 
                   1381:        /* ask for a passive connection if we need one */
                   1382:        if (ftp->pasv && !ftp_pasv(ftp, 1)) {
                   1383:                return NULL;
                   1384:        }
                   1385:        /* alloc the data structure */
                   1386:        data = ecalloc(1, sizeof(*data));
                   1387:        data->listener = -1;
                   1388:        data->fd = -1;
                   1389:        data->type = ftp->type;
                   1390: 
                   1391:        sa = (struct sockaddr *) &ftp->localaddr;
                   1392:        /* bind/listen */
                   1393:        if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == SOCK_ERR) {
                   1394:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "socket() failed: %s (%d)", strerror(errno), errno);
                   1395:                goto bail;
                   1396:        }
                   1397: 
                   1398:        /* passive connection handler */
                   1399:        if (ftp->pasv) {
                   1400:                /* clear the ready status */
                   1401:                ftp->pasv = 1;
                   1402: 
                   1403:                /* connect */
                   1404:                /* Win 95/98 seems not to like size > sizeof(sockaddr_in) */
                   1405:                size = php_sockaddr_size(&ftp->pasvaddr);
                   1406:                tv.tv_sec = ftp->timeout_sec;
                   1407:                tv.tv_usec = 0;
                   1408:                if (php_connect_nonb(fd, (struct sockaddr*) &ftp->pasvaddr, size, &tv) == -1) {
                   1409:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_connect_nonb() failed: %s (%d)", strerror(errno), errno);
                   1410:                        goto bail;
                   1411:                }
                   1412: 
                   1413:                data->fd = fd;
                   1414: 
                   1415:                ftp->data = data;
                   1416:                return data;
                   1417:        }
                   1418: 
                   1419: 
                   1420:        /* active (normal) connection */
                   1421: 
                   1422:        /* bind to a local address */
                   1423:        php_any_addr(sa->sa_family, &addr, 0);
                   1424:        size = php_sockaddr_size(&addr);
                   1425: 
                   1426:        if (bind(fd, (struct sockaddr*) &addr, size) != 0) {
                   1427:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "bind() failed: %s (%d)", strerror(errno), errno);
                   1428:                goto bail;
                   1429:        }
                   1430: 
                   1431:        if (getsockname(fd, (struct sockaddr*) &addr, &size) != 0) {
                   1432:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "getsockname() failed: %s (%d)", strerror(errno), errno);
                   1433:                goto bail;
                   1434:        }
                   1435: 
                   1436:        if (listen(fd, 5) != 0) {
                   1437:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "listen() failed: %s (%d)", strerror(errno), errno);
                   1438:                goto bail;
                   1439:        }
                   1440: 
                   1441:        data->listener = fd;
                   1442: 
                   1443: #if HAVE_IPV6 && HAVE_INET_NTOP
                   1444:        if (sa->sa_family == AF_INET6) {
                   1445:                /* need to use EPRT */
                   1446:                char eprtarg[INET6_ADDRSTRLEN + sizeof("|x||xxxxx|")];
                   1447:                char out[INET6_ADDRSTRLEN];
                   1448:                inet_ntop(AF_INET6, &((struct sockaddr_in6*) sa)->sin6_addr, out, sizeof(out));
                   1449:                snprintf(eprtarg, sizeof(eprtarg), "|2|%s|%hu|", out, ntohs(((struct sockaddr_in6 *) &addr)->sin6_port));
                   1450: 
                   1451:                if (!ftp_putcmd(ftp, "EPRT", eprtarg)) {
                   1452:                        goto bail;
                   1453:                }
                   1454: 
                   1455:                if (!ftp_getresp(ftp) || ftp->resp != 200) {
                   1456:                        goto bail;
                   1457:                }
                   1458: 
                   1459:                ftp->data = data;
                   1460:                return data;
                   1461:        }
                   1462: #endif
                   1463: 
                   1464:        /* send the PORT */
                   1465:        ipbox.ia[0] = ((struct sockaddr_in*) sa)->sin_addr;
                   1466:        ipbox.s[2] = ((struct sockaddr_in*) &addr)->sin_port;
                   1467:        snprintf(arg, sizeof(arg), "%u,%u,%u,%u,%u,%u", ipbox.c[0], ipbox.c[1], ipbox.c[2], ipbox.c[3], ipbox.c[4], ipbox.c[5]);
                   1468: 
                   1469:        if (!ftp_putcmd(ftp, "PORT", arg)) {
                   1470:                goto bail;
                   1471:        }
                   1472:        if (!ftp_getresp(ftp) || ftp->resp != 200) {
                   1473:                goto bail;
                   1474:        }
                   1475: 
                   1476:        ftp->data = data;
                   1477:        return data;
                   1478: 
                   1479: bail:
                   1480:        if (fd != -1) {
                   1481:                closesocket(fd);
                   1482:        }
                   1483:        efree(data);
                   1484:        return NULL;
                   1485: }
                   1486: /* }}} */
                   1487: 
                   1488: /* {{{ data_accept
                   1489:  */
                   1490: databuf_t*
                   1491: data_accept(databuf_t *data, ftpbuf_t *ftp TSRMLS_DC)
                   1492: {
                   1493:        php_sockaddr_storage addr;
                   1494:        socklen_t                       size;
                   1495: 
                   1496: #if HAVE_OPENSSL_EXT
                   1497:        SSL_CTX         *ctx;
                   1498: #endif
                   1499: 
                   1500:        if (data->fd != -1) {
                   1501:                goto data_accepted;
                   1502:        }
                   1503:        size = sizeof(addr);
                   1504:        data->fd = my_accept(ftp, data->listener, (struct sockaddr*) &addr, &size);
                   1505:        closesocket(data->listener);
                   1506:        data->listener = -1;
                   1507: 
                   1508:        if (data->fd == -1) {
                   1509:                efree(data);
                   1510:                return NULL;
                   1511:        }
                   1512: 
                   1513: data_accepted:
                   1514: #if HAVE_OPENSSL_EXT
                   1515:        
                   1516:        /* now enable ssl if we need to */
                   1517:        if (ftp->use_ssl && ftp->use_ssl_for_data) {
                   1518:                ctx = SSL_CTX_new(SSLv23_client_method());
                   1519:                if (ctx == NULL) {
                   1520:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: failed to create the SSL context");
                   1521:                        return 0;
                   1522:                }
                   1523: 
                   1524:                SSL_CTX_set_options(ctx, SSL_OP_ALL);
                   1525: 
                   1526:                data->ssl_handle = SSL_new(ctx);
                   1527:                if (data->ssl_handle == NULL) {
                   1528:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: failed to create the SSL handle");
                   1529:                        SSL_CTX_free(ctx);
                   1530:                        return 0;
                   1531:                }
                   1532:                        
                   1533:                
                   1534:                SSL_set_fd(data->ssl_handle, data->fd);
                   1535: 
                   1536:                if (ftp->old_ssl) {
                   1537:                        SSL_copy_session_id(data->ssl_handle, ftp->ssl_handle);
                   1538:                }
                   1539:                        
                   1540:                if (SSL_connect(data->ssl_handle) <= 0) {
                   1541:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: SSL/TLS handshake failed");
                   1542:                        SSL_shutdown(data->ssl_handle);
                   1543:                        return 0;
                   1544:                }
                   1545:                        
                   1546:                data->ssl_active = 1;
                   1547:        }       
                   1548: 
                   1549: #endif
                   1550: 
                   1551:        return data;
                   1552: }
                   1553: /* }}} */
                   1554: 
                   1555: /* {{{ data_close
                   1556:  */
                   1557: databuf_t*
                   1558: data_close(ftpbuf_t *ftp, databuf_t *data)
                   1559: {
                   1560:        if (data == NULL) {
                   1561:                return NULL;
                   1562:        }
                   1563:        if (data->listener != -1) {
                   1564: #if HAVE_OPENSSL_EXT
                   1565:                if (data->ssl_active) {
                   1566:                        SSL_shutdown(data->ssl_handle);
                   1567:                        data->ssl_active = 0;
                   1568:                }
                   1569: #endif                         
                   1570:                closesocket(data->listener);
                   1571:        }       
                   1572:        if (data->fd != -1) {
                   1573: #if HAVE_OPENSSL_EXT
                   1574:                if (data->ssl_active) {
                   1575:                        SSL_shutdown(data->ssl_handle);
                   1576:                        data->ssl_active = 0;
                   1577:                }
                   1578: #endif                         
                   1579:                closesocket(data->fd);
                   1580:        }       
                   1581:        if (ftp) {
                   1582:                ftp->data = NULL;
                   1583:        }
                   1584:        efree(data);
                   1585:        return NULL;
                   1586: }
                   1587: /* }}} */
                   1588: 
                   1589: /* {{{ ftp_genlist
                   1590:  */
                   1591: char**
                   1592: ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC)
                   1593: {
                   1594:        php_stream      *tmpstream = NULL;
                   1595:        databuf_t       *data = NULL;
                   1596:        char            *ptr;
                   1597:        int             ch, lastch;
                   1598:        int             size, rcvd;
                   1599:        int             lines;
                   1600:        char            **ret = NULL;
                   1601:        char            **entry;
                   1602:        char            *text;
                   1603: 
                   1604: 
                   1605:        if ((tmpstream = php_stream_fopen_tmpfile()) == NULL) {
                   1606:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create temporary file.  Check permissions in temporary files directory.");
                   1607:                return NULL;
                   1608:        }
                   1609: 
                   1610:        if (!ftp_type(ftp, FTPTYPE_ASCII)) {
                   1611:                goto bail;
                   1612:        }
                   1613: 
                   1614:        if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
                   1615:                goto bail;
                   1616:        }
                   1617:        ftp->data = data;       
                   1618: 
                   1619:        if (!ftp_putcmd(ftp, cmd, path)) {
                   1620:                goto bail;
                   1621:        }
                   1622:        if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125 && ftp->resp != 226)) {
                   1623:                goto bail;
                   1624:        }
                   1625: 
                   1626:        /* some servers don't open a ftp-data connection if the directory is empty */
                   1627:        if (ftp->resp == 226) {
                   1628:                ftp->data = data_close(ftp, data);
                   1629:                php_stream_close(tmpstream);
                   1630:                return ecalloc(1, sizeof(char**));
                   1631:        }
                   1632: 
                   1633:        /* pull data buffer into tmpfile */
                   1634:        if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
                   1635:                goto bail;
                   1636:        }
                   1637:        size = 0;
                   1638:        lines = 0;
                   1639:        lastch = 0;
                   1640:        while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
                   1641:                if (rcvd == -1) {
                   1642:                        goto bail;
                   1643:                }
                   1644: 
                   1645:                php_stream_write(tmpstream, data->buf, rcvd);
                   1646: 
                   1647:                size += rcvd;
                   1648:                for (ptr = data->buf; rcvd; rcvd--, ptr++) {
                   1649:                        if (*ptr == '\n' && lastch == '\r') {
                   1650:                                lines++;
                   1651:                        } else {
                   1652:                                size++;
                   1653:                        }
                   1654:                        lastch = *ptr;
                   1655:                }
                   1656:        }
                   1657: 
                   1658:        ftp->data = data = data_close(ftp, data);
                   1659: 
                   1660:        php_stream_rewind(tmpstream);
                   1661: 
                   1662:        ret = safe_emalloc((lines + 1), sizeof(char**), size * sizeof(char*));
                   1663: 
                   1664:        entry = ret;
                   1665:        text = (char*) (ret + lines + 1);
                   1666:        *entry = text;
                   1667:        lastch = 0;
                   1668:        while ((ch = php_stream_getc(tmpstream)) != EOF) {
                   1669:                if (ch == '\n' && lastch == '\r') {
                   1670:                        *(text - 1) = 0;
                   1671:                        *++entry = text;
                   1672:                } else {
                   1673:                        *text++ = ch;
                   1674:                }
                   1675:                lastch = ch;
                   1676:        }
                   1677:        *entry = NULL;
                   1678: 
                   1679:        php_stream_close(tmpstream);
                   1680: 
                   1681:        if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
                   1682:                efree(ret);
                   1683:                return NULL;
                   1684:        }
                   1685: 
                   1686:        return ret;
                   1687: bail:
                   1688:        ftp->data = data_close(ftp, data);
                   1689:        php_stream_close(tmpstream);
                   1690:        if (ret)
                   1691:                efree(ret);
                   1692:        return NULL;
                   1693: }
                   1694: /* }}} */
                   1695: 
                   1696: /* {{{ ftp_nb_get
                   1697:  */
                   1698: int
                   1699: ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, int resumepos TSRMLS_DC)
                   1700: {
                   1701:        databuf_t               *data = NULL;
                   1702:        char                    arg[11];
                   1703: 
                   1704:        if (ftp == NULL) {
                   1705:                return PHP_FTP_FAILED;
                   1706:        }
                   1707: 
                   1708:        if (!ftp_type(ftp, type)) {
                   1709:                goto bail;
                   1710:        }
                   1711: 
                   1712:        if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
                   1713:                goto bail;
                   1714:        }
                   1715: 
                   1716:        if (resumepos>0) {
                   1717:                /* We are working on an architecture that supports 64-bit integers
                   1718:                 * since php is 32 bit by design, we bail out with warning
                   1719:                 */
                   1720:                if (resumepos > 2147483647) {
                   1721:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP cannot handle files greater than 2147483648 bytes.");
                   1722:                        goto bail;
                   1723:                }
                   1724:                snprintf(arg, sizeof(arg), "%u", resumepos);
                   1725:                if (!ftp_putcmd(ftp, "REST", arg)) {
                   1726:                        goto bail;
                   1727:                }
                   1728:                if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
                   1729:                        goto bail;
                   1730:                }
                   1731:        }
                   1732: 
                   1733:        if (!ftp_putcmd(ftp, "RETR", path)) {
                   1734:                goto bail;
                   1735:        }
                   1736:        if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
                   1737:                goto bail;
                   1738:        }
                   1739: 
                   1740:        if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
                   1741:                goto bail;
                   1742:        }
                   1743: 
                   1744:        ftp->data = data;
                   1745:        ftp->stream = outstream;
                   1746:        ftp->lastch = 0;
                   1747:        ftp->nb = 1;
                   1748: 
                   1749:        return (ftp_nb_continue_read(ftp TSRMLS_CC));
                   1750: 
                   1751: bail:
                   1752:        ftp->data = data_close(ftp, data);
                   1753:        return PHP_FTP_FAILED;
                   1754: }
                   1755: /* }}} */
                   1756: 
                   1757: /* {{{ ftp_nb_continue_read
                   1758:  */
                   1759: int
                   1760: ftp_nb_continue_read(ftpbuf_t *ftp TSRMLS_DC)
                   1761: {
                   1762:        databuf_t       *data = NULL;
                   1763:        char            *ptr;
                   1764:        int             lastch;
                   1765:        size_t          rcvd;
                   1766:        ftptype_t       type;
                   1767: 
                   1768:        data = ftp->data;
                   1769: 
                   1770:        /* check if there is already more data */
                   1771:        if (!data_available(ftp, data->fd)) {
                   1772:                return PHP_FTP_MOREDATA;
                   1773:        }
                   1774: 
                   1775:        type = ftp->type;
                   1776: 
                   1777:        lastch = ftp->lastch;
                   1778:        if ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
                   1779:                if (rcvd == -1) {
                   1780:                        goto bail;
                   1781:                }
                   1782: 
                   1783:                if (type == FTPTYPE_ASCII) {
                   1784:                        for (ptr = data->buf; rcvd; rcvd--, ptr++) {
                   1785:                                if (lastch == '\r' && *ptr != '\n') {
                   1786:                                        php_stream_putc(ftp->stream, '\r');
                   1787:                                }
                   1788:                                if (*ptr != '\r') {
                   1789:                                        php_stream_putc(ftp->stream, *ptr);
                   1790:                                }
                   1791:                                lastch = *ptr;
                   1792:                        }
                   1793:                } else if (rcvd != php_stream_write(ftp->stream, data->buf, rcvd)) {
                   1794:                        goto bail;
                   1795:                }
                   1796: 
                   1797:                ftp->lastch = lastch;
                   1798:                return PHP_FTP_MOREDATA;
                   1799:        }
                   1800: 
                   1801:        if (type == FTPTYPE_ASCII && lastch == '\r') {
                   1802:                php_stream_putc(ftp->stream, '\r');
                   1803:        }
                   1804: 
                   1805:        ftp->data = data = data_close(ftp, data);
                   1806: 
                   1807:        if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
                   1808:                goto bail;
                   1809:        }
                   1810: 
                   1811:        ftp->nb = 0;
                   1812:        return PHP_FTP_FINISHED;
                   1813: bail:
                   1814:        ftp->nb = 0;
                   1815:        ftp->data = data_close(ftp, data);
                   1816:        return PHP_FTP_FAILED;
                   1817: }
                   1818: /* }}} */
                   1819: 
                   1820: /* {{{ ftp_nb_put
                   1821:  */
                   1822: int
                   1823: ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, int startpos TSRMLS_DC)
                   1824: {
                   1825:        databuf_t               *data = NULL;
                   1826:        char                    arg[11];
                   1827: 
                   1828:        if (ftp == NULL) {
                   1829:                return 0;
                   1830:        }
                   1831:        if (!ftp_type(ftp, type)) {
                   1832:                goto bail;
                   1833:        }
                   1834:        if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
                   1835:                goto bail;
                   1836:        }
                   1837:        if (startpos > 0) {
                   1838:                if (startpos > 2147483647) {
                   1839:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP cannot handle files with a size greater than 2147483647 bytes.");
                   1840:                        goto bail;
                   1841:                }
                   1842:                snprintf(arg, sizeof(arg), "%u", startpos);
                   1843:                if (!ftp_putcmd(ftp, "REST", arg)) {
                   1844:                        goto bail;
                   1845:                }
                   1846:                if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
                   1847:                        goto bail;
                   1848:                }
                   1849:        }
                   1850: 
                   1851:        if (!ftp_putcmd(ftp, "STOR", path)) {
                   1852:                goto bail;
                   1853:        }
                   1854:        if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
                   1855:                goto bail;
                   1856:        }
                   1857:        if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) { 
                   1858:                goto bail;
                   1859:        }
                   1860:        ftp->data = data;
                   1861:        ftp->stream = instream;
                   1862:        ftp->lastch = 0;
                   1863:        ftp->nb = 1;
                   1864: 
                   1865:        return (ftp_nb_continue_write(ftp TSRMLS_CC));
                   1866: 
                   1867: bail:
                   1868:        ftp->data = data_close(ftp, data);
                   1869:        return PHP_FTP_FAILED;
                   1870: }
                   1871: /* }}} */
                   1872: 
                   1873: 
                   1874: /* {{{ ftp_nb_continue_write
                   1875:  */
                   1876: int
                   1877: ftp_nb_continue_write(ftpbuf_t *ftp TSRMLS_DC)
                   1878: {
                   1879:        int                     size;
                   1880:        char                    *ptr;
                   1881:        int                     ch;
                   1882: 
                   1883:        /* check if we can write more data */
                   1884:        if (!data_writeable(ftp, ftp->data->fd)) {
                   1885:                return PHP_FTP_MOREDATA;
                   1886:        }
                   1887: 
                   1888:        size = 0;
                   1889:        ptr = ftp->data->buf;
                   1890:        while (!php_stream_eof(ftp->stream) && (ch = php_stream_getc(ftp->stream)) != EOF) {
                   1891: 
                   1892:                if (ch == '\n' && ftp->type == FTPTYPE_ASCII) {
                   1893:                        *ptr++ = '\r';
                   1894:                        size++;
                   1895:                }
                   1896: 
                   1897:                *ptr++ = ch;
                   1898:                size++;
                   1899: 
                   1900:                /* flush if necessary */
                   1901:                if (FTP_BUFSIZE - size < 2) {
                   1902:                        if (my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
                   1903:                                goto bail;
                   1904:                        }
                   1905:                        return PHP_FTP_MOREDATA;
                   1906:                }
                   1907:        }
                   1908: 
                   1909:        if (size && my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
                   1910:                goto bail;
                   1911:        }
                   1912:        ftp->data = data_close(ftp, ftp->data);
                   1913:  
                   1914:        if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
                   1915:                goto bail;
                   1916:        }
                   1917:        ftp->nb = 0;
                   1918:        return PHP_FTP_FINISHED;
                   1919: bail:
                   1920:        ftp->data = data_close(ftp, ftp->data);
                   1921:        ftp->nb = 0;
                   1922:        return PHP_FTP_FAILED;
                   1923: }
                   1924: /* }}} */
                   1925: 
                   1926: #endif /* HAVE_FTP */
                   1927: 
                   1928: /*
                   1929:  * Local variables:
                   1930:  * tab-width: 4
                   1931:  * c-basic-offset: 4
                   1932:  * End:
                   1933:  * vim600: sw=4 ts=4 fdm=marker
                   1934:  * vim<600: sw=4 ts=4
                   1935:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>