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

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

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