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

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

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