ShellBanner
System:Linux MiraNet 3.0.0-14-generic-pae #23-Ubuntu SMP Mon Nov 21 22:07:10 UTC 2011 i686
Software:Apache. PHP/5.3.6-13ubuntu3.10
ID:uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
Safe Mode:OFF
Open_Basedir:OFF
Freespace:25.71 GB of 70.42 GB (36.51%)
MySQL: ON MSSQL: OFF Oracle: OFF PostgreSQL: OFF Curl: OFF Sockets: ON Fetch: OFF Wget: ON Perl: ON
Disabled Functions: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,

/ usr/ src/ courier-0.66.1/ pcp/ - drwxrwxrwx

Directory:
Viewing file:     pcpnet.c (35.09 KB)      -rw-rw-rw-
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
** Copyright 2001-2002 Double Precision, Inc.  See COPYING for
** distribution information.
*/


#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/un.h>
#include <rfc822/rfc822hdr.h>
#include "pcp.h"
#include "calendardir.h"

#if HAVE_DIRENT_H
#include <dirent.h>
#else
#define dirent direct
#if HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#if HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#if HAVE_NDIR_H
#include <ndir.h>
#endif
#endif

#define HOSTNAMELEN 256

#define EVENTID_MAXLEN 512
#define ADDR_MAXLEN 512

#define EVENTID_SSCANF "%511s"
#define ADDR_SSCANF "%511s"

struct PCPnet {
    struct PCP pcp;
    char *username;
    char *authtoken;
    char *sockname;
    int fd;

    char *readbuf;
    size_t readbuflen;

    char *readptr;
    size_t readleft;

    int haserrmsg;
} ;

struct PCPnet_new_eventid {
    struct PCP_new_eventid eventid;
    int isbooked;
} ;

static void pcp_close_quit_net(struct PCPnet *);
static void pcp_close_net(struct PCPnet *);
static int cleanup(struct PCPnet *);

static struct PCP_new_eventid *neweventid(struct PCPnet *,
                      const char *,
                      struct PCP_save_event *);
static void destroyeventid(struct PCPnet *, struct PCPnet_new_eventid *);

static int commitevent(struct PCPnet *, struct PCPnet_new_eventid *,
               struct PCP_commit *);
static int bookevent(struct PCPnet *, struct PCPnet_new_eventid *,
             struct PCP_commit *);

static int listallevents(struct PCPnet *, struct PCP_list_all *);

static int cancelevent(struct PCPnet *, const char *, int *);
static int uncancelevent(struct PCPnet *, const char *,
             int, struct PCP_uncancel *);
static int deleteevent(struct PCPnet *, struct PCP_delete *);
static int retrevent(struct PCPnet *, struct PCP_retr *);
static int setacl(struct PCPnet *, const char *, int);
static int listacl(struct PCPnet *,
           int (*)(const char *, int, void *),
           void *);
static void noop(struct PCPnet *);

static const char *getauthtoken(struct PCPnet *pcp)
{
    return (pcp->authtoken);
}

static const char *errmsg(struct PCPnet *pcp)
{
    if (pcp->haserrmsg)
        return (pcp->readbuf);
    return (strerror(errno));
}

static struct PCPnet *mkpcp(const char *username)
{
    struct PCPnet *pd=(struct PCPnet *)malloc(sizeof(struct PCPnet));
    const char *p;

    if (!pd)
        return (NULL);

    if (!*username)
    {
        free(pd);
        errno=EIO;
        return (NULL);
    }

    for (p=username; *p; p++)
        if (isspace((int)(unsigned char)*p))
        {
            free(pd);
            errno=EIO;
            return (NULL);
        }

    memset(pd, 0, sizeof(*pd));

    pd->fd= -1;
    pd->username=strdup(username);
    if (!pd->username)
    {
        free(pd);
        return (NULL);
    }

    pd->pcp.authtoken_func=(const char *(*)(struct PCP *))getauthtoken;
    pd->pcp.close_func= (void (*)(struct PCP *)) pcp_close_quit_net;
    pd->pcp.cleanup_func= (int (*)(struct PCP *)) cleanup;

    pd->pcp.create_new_eventid_func=
        (struct PCP_new_eventid *(*)(struct PCP *, const char *,
                         struct PCP_save_event *))
        neweventid;

    pd->pcp.destroy_new_eventid_func=
        (void (*)(struct PCP *, struct PCP_new_eventid *))
        destroyeventid;

    pd->pcp.commit_func=
        (int (*)(struct PCP *, struct PCP_new_eventid *,
             struct PCP_commit *))
        commitevent;

    pd->pcp.book_func=
        (int (*)(struct PCP *, struct PCP_new_eventid *,
             struct PCP_commit *))
        bookevent;

    pd->pcp.list_all_func=
        (int (*)(struct PCP *, struct PCP_list_all *))
        listallevents;

    pd->pcp.cancel_func=
        (int (*)(struct PCP *, const char *, int *))
        cancelevent;

    pd->pcp.uncancel_func=
        (int (*)(struct PCP *, const char *, int,
             struct PCP_uncancel *))
        uncancelevent;

    pd->pcp.delete_func=
        (int (*)(struct PCP *, struct PCP_delete *))
        deleteevent;

    pd->pcp.retr_func=
        (int (*)(struct PCP *, struct PCP_retr *))
        retrevent;

    pd->pcp.errmsg_func=
        (const char *(*)(struct PCP *))
        errmsg;

    pd->pcp.noop_func=(void (*)(struct PCP *))noop;

    pd->pcp.acl_func=
        (int (*)(struct PCP *, const char *, int))setacl;
    pd->pcp.listacl_func=
        (int (*)(struct PCP *, int (*)(const char *, int, void *),
             void *))listacl;

    return (pd);
}

struct sock_list {
    struct sock_list *next;
    char *filename;
} ;

static int cmp_str(const void *a, const void *b)
{
    return (strcmp(*(const char **)a, *(const char **)b));
}

static int dowrite(struct PCPnet *pcp, const char *s, int l)
{
    if (l <= 0)
        l=strlen(s);

    if (pcp->fd < 0)
    {
        errno=ENETDOWN;
        return (-1);
    }

    while (l)
    {
        int n=write(pcp->fd, s, l);

        if (n <= 0)
        {
            errno=ENETDOWN;
            close(pcp->fd);
            pcp->fd= -1;
            return (-1);
        }

        s += n;
        l -= n;
    }
    return (0);
}

static int readch(struct PCPnet *pcp, size_t n)
{
    if (pcp->readleft == 0)
    {
        int l;
        struct timeval tv;
        fd_set fds;

        /* Read the next chunk after the current line :-) */

        if (n + BUFSIZ > pcp->readbuflen)
        {
            size_t nn=n+BUFSIZ;
            char *p= pcp->readbuf ?
                realloc(pcp->readbuf, nn):malloc(nn);
            if (!p)
            {
                close(pcp->fd);
                pcp->fd= -1;
                return (-1);
            }
            pcp->readbuf=p;
            pcp->readbuflen=nn;
        }

        pcp->readptr=pcp->readbuf + n;

        FD_ZERO(&fds);
        FD_SET(pcp->fd, &fds);
        tv.tv_sec=300;
        tv.tv_usec=0;
        if (select(pcp->fd+1, &fds, NULL, NULL, &tv) <= 0)
        {
            errno=ETIMEDOUT;
            close(pcp->fd);
            pcp->fd= -1;
            return (EOF);
        }
        l=read(pcp->fd, pcp->readptr, BUFSIZ);
        if (l <= 0)
        {
            if (l == 0)
                errno=0;
            close(pcp->fd);
            pcp->fd= -1;
            errno=ECONNRESET;
            return (EOF);
        }
        pcp->readleft=l;
    }

    --pcp->readleft;
    return ((int)(unsigned char)*pcp->readptr++);
}

static int getfullreply(struct PCPnet *pcp)
{
    size_t n=0;
    int ch;

    for (;;)
    {
        size_t nn=n;

        while ((ch=readch(pcp, nn)) != EOF)
        {
            if (ch == '\n')
                break;
            pcp->readbuf[nn++]=ch;
        }

        if (ch == EOF)
            return (-1);

        if (nn-n >= 4 &&
            isdigit((int)(unsigned char)pcp->readbuf[n]) &&
            isdigit((int)(unsigned char)pcp->readbuf[n+1]) &&
            isdigit((int)(unsigned char)pcp->readbuf[n+2]) &&
            isspace((int)(unsigned char)pcp->readbuf[n+3]))
        {
            pcp->readbuf[nn]=0;
            break;
        }
        n= ++nn;
    }

    return (0);
}

static int getonelinereply(struct PCPnet *pcp)
{
    size_t nn;
    int islast;

    nn=0;
    for (;;)
    {
        int ch;

        while ((ch=readch(pcp, nn)) != EOF)
        {
            if (ch == '\n')
                break;
            pcp->readbuf[nn++]=ch;
            if (nn >= 8192)
                nn=8192;
        }
        pcp->readbuf[nn]=0;
        if (ch == EOF)
            return (-1);

        if (!isdigit((int)(unsigned char)pcp->readbuf[0])
            || !isdigit((int)(unsigned char)pcp->readbuf[1])
            || !isdigit((int)(unsigned char)pcp->readbuf[2]))
        {
            nn=0;
            continue;
        }
        islast= pcp->readbuf[3] != '-';
        break;
    }
    return (islast);
}


static int docmd(struct PCPnet *pcp, const char *cmd, int cmdl)
{
    if (dowrite(pcp, cmd, cmdl) < 0)
        return (-1);
    return (getfullreply(pcp));
}

static int checkstatus(struct PCPnet *pcp, int *errcode)
{
    const char *p=strrchr(pcp->readbuf, '\n');
    int n;

    if (p)
        ++p;
    else
        p=pcp->readbuf;
    n=atoi(p);
    if (errcode)
        switch (n) {
        case 504:
            *errcode=PCP_ERR_EVENTNOTFOUND;
            break;
        case 506:
            *errcode=PCP_ERR_EVENTLOCKED;
            break;
        }
    return (n);
}

static char *getword(struct PCPnet *pcp, char **p)
{
    char *q;

    while (**p && isspace((int)(unsigned char)**p))
        ++*p;

    if (!**p)
        return (NULL);
    q= *p;

    while (**p && !isspace((int)(unsigned char)**p))
        ++*p;

    if (**p)
    {
        **p=0;
        ++*p;
    }
    return (q);
}

/* Parse 102 response */

static int parseauthtoken(struct PCPnet *pcp)
{
    char *p=pcp->readbuf;
    char *q;

    getword(pcp, &p);    /* skip 102 */

    q=getword(pcp, &p);

    if (!q)
    {
        errno=EIO;
        return (-1);
    }

    if (pcp->authtoken)
        free(pcp->authtoken);

    if ((p=strrchr(pcp->sockname, '/')) != 0)
        ++p;
    else
        p=pcp->sockname;

    if ((pcp->authtoken=malloc(strlen(p)+strlen(q)+2)) == NULL)
        return (-1);
    strcat(strcat(strcpy(pcp->authtoken, p), "/"), q);
    return (0);
}

/* Parse 100 response */

static int has100(struct PCPnet *pcp, const char *kw)
{
    char *p=pcp->readbuf;
    int l = strlen(kw);

    while (*p)
    {
        while (isdigit((int)(unsigned char)*p))
            ++p;
        if (*p != '\n')
            ++p;

        if (strncasecmp(p, kw, l) == 0 &&
            (p[l] == 0 || isspace((int)(unsigned char)p[l])))
            return (1);

        while (*p)
            if (*p++ == '\n')
                break;
    }
    return (0);
}

static int doconnect(struct PCPnet *pcp, const char *dir, const char *username,
             const char *sockname,
             const char *clustername,
             char **errmsg)
{
    DIR *dirp=opendir(dir);
    struct sock_list *l=NULL;
    struct dirent *de;
    struct sock_list *nl;
    unsigned i,cnt=0;
    char **a;
    int fd;
    char *buf;
    int clustername_l=clustername ? strlen(clustername):0;

    if (errmsg)
        *errmsg=0;

    while (dirp && (de=readdir(dirp)) != NULL)
    {
        if (strchr(de->d_name, '.'))
            continue;

        if (sockname && strcmp(de->d_name, sockname))
            continue;

        /*
        ** When the proxy connection comes in via the proxy cluster,
        ** ignore the proxy cluster client's socket, so we don't end
        ** up in an infinite loop!
        */

        if (clustername)
        {
            const char *p=de->d_name;

            while (p && isdigit((int)(unsigned char)*p))
                ++p;

            if (strncasecmp(p, clustername, clustername_l) == 0
                && p[clustername_l] == '.')
                continue;
        }

        nl=malloc(sizeof(struct sock_list));

        if (!nl || (nl->filename=malloc(strlen(dir)+2+
                        strlen(de->d_name))) == NULL)
        {
            if (nl) free(nl);

            while ((nl=l) != NULL)
            {
                l=nl->next;
                free(nl->filename);
                free(nl);
            }
            return (-1);
        }
        strcat(strcat(strcpy(nl->filename, dir), "/"), de->d_name);
        ++cnt;
        nl->next=l;
        l=nl;
    }

    if (dirp)
        closedir(dirp);

    if (!l)
    {
        errno=ENOENT;
        return (-1);
    }

    if ((a=malloc(sizeof(char *)*cnt)) == NULL)
    {
        while ((nl=l) != NULL)
        {
            l=nl->next;
            free(nl->filename);
            free(nl);
        }
        return (-1);
    }

    cnt=0;
    for (nl=l; nl; nl=nl->next)
        a[cnt++]=nl->filename;

    qsort(a, cnt, sizeof(*a), cmp_str);

    fd= -1;

    for (i=0; i<cnt; i++)
    {
        struct  sockaddr_un skun;
        int rc;

        fd=socket(PF_UNIX, SOCK_STREAM, 0);
        if (fd < 0)
            break;

        skun.sun_family=AF_UNIX;
        strcpy(skun.sun_path, a[i]);

        if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
        {
            close(fd);
            fd= -1;
            break;
        }

        if ( pcp->sockname )
            free(pcp->sockname);
        if ( (pcp->sockname=strdup(a[i])) == NULL)
        {
            close(fd);
            fd= -1;
            break;
        }

        if ( connect(fd,
                 (const struct sockaddr *)&skun,
                 sizeof(skun)) == 0)
        {
            /* That was easy, we're done. */

            if (fcntl(fd, F_SETFL, 0) < 0)
            {
                close(fd);
                fd= -1;
                break;
            }
        }
        else if ( errno != EINPROGRESS && errno != EWOULDBLOCK)
        {
            close(fd);
            fd= -1;
            break;
        }
        else
        {
            struct timeval tv;
            fd_set fdr;
            int rc;

            FD_ZERO(&fdr);
            FD_SET(fd, &fdr);
            tv.tv_sec=30;
            tv.tv_usec=0;

            rc=select(fd+1, 0, &fdr, 0, &tv);
            if (rc <= 0 || !FD_ISSET(fd, &fdr))
            {
                close(fd);
                fd= -1;
                break;
            }

            if ( connect(fd, (const struct sockaddr *)&skun,
                     sizeof(skun)))
            {
                if (errno != EISCONN)
                {
                    close(fd);
                    break;
                }
            }

            if (fcntl(fd, F_SETFL, 0) < 0)
            {
                close(fd);
                break;
            }
        }

        pcp->fd=fd;
        if (docmd(pcp, "CAPABILITY\n", 0))
        {
            fd= -1;
            break;
        }

        if ((rc=checkstatus(pcp, NULL)) != 100)
        {
            close(fd);
            fd= -1;
            continue;
        }

        if (!has100(pcp, "PCP1"))
        {
            close(fd);
            fd= -1;
            continue;
        }

        buf=malloc(strlen(username)+sizeof("USERID \n"));
        if (buf == 0)
        {
            close(fd);
            fd= -1;
            break;

        }

        strcat(strcat(strcpy(buf, "USERID "), username), "\n");

        if (docmd(pcp, buf, 0))
        {
            fd= -1;
            free(buf);
            break;
        }
        pcp->fd= -1;
        free(buf);

        switch ((rc=checkstatus(pcp, NULL)) / 100) {
        case 1:
        case 2:
        case 3:
            break;
        default:
            errno=EIO;
            if (errmsg)
            {
                if (*errmsg)
                    free(*errmsg);
                *errmsg=strdup(pcp->readbuf);
            }
            close(fd);
            fd= -1;
            break;
        case 5:
            errno=ENOENT;
            if (errmsg)
            {
                if (*errmsg)
                    free(*errmsg);
                *errmsg=strdup("Calendar not found.");
            }
            close(fd);
            fd= -1;
            continue;
        }

        if (rc == 102)
        {
            if (parseauthtoken(pcp))
            {
                close(fd);
                fd= -1;
            }
            break;
        }
        break;
    }

    free(a);
    while ((nl=l) != NULL)
    {
        l=nl->next;
        free(nl->filename);
        free(nl);
    }
    return (fd);
}

static struct PCP *setcapabilities(struct PCPnet *, int);

struct PCP *pcp_open_server(const char *username, const char *password,
                char **errmsg)
{
    struct PCPnet *pcp=mkpcp(username);

    if (errmsg)
        *errmsg=0;
    if (!pcp)
        return (NULL);

    if (strchr(username, '\r') || strchr(username, '\n'))
    {
        errno=EINVAL;
        pcp_close_net(pcp);
        return (NULL);
    }

    if (strchr(password, '\r') || strchr(password, '\n'))
    {
        errno=EINVAL;
        pcp_close_net(pcp);
        return (NULL);
    }


    if ((pcp->fd=doconnect(pcp, CALENDARDIR "/public", username, NULL,
                   NULL, errmsg)) < 0)
    {
        pcp_close_net(pcp);
        return (NULL);
    }

    if (pcp->authtoken == NULL)
    {
        char *buf;
        int rc;

        if (strchr(password, '\n') || strchr(password, '\r'))
        {
            errno=EINVAL;
            pcp_close_net(pcp);
            return (NULL);
        }

        buf=malloc(strlen(password)+sizeof("PASSWORD \n"));
        if (buf == 0)
        {
            pcp_close_net(pcp);
            return (NULL);
        }

        strcat(strcat(strcpy(buf, "PASSWORD "), password), "\n");

        if (docmd(pcp, buf, 0))
        {
            free(buf);
            pcp_close_net(pcp);
            return (NULL);
        }
        free(buf);

        switch ((rc=checkstatus(pcp, NULL)) / 100) {
        case 1:
        case 2:
        case 3:
            break;
        default:
            if (errmsg)
            {
                if (*errmsg)
                    free(*errmsg);
                *errmsg=strdup(pcp->readbuf);
            }
            pcp_close_net(pcp);
            errno=EPERM;
            return (NULL);
        }

        if (rc == 102)
        {
            if (parseauthtoken(pcp))
            {
                pcp_close_net(pcp);
                return (NULL);
            }
        }
    }

    return (setcapabilities(pcp, 1));
}

static struct PCP *setcapabilities(struct PCPnet *pcp, int dofree)
{
    int rc;

    if (docmd(pcp, "CAPABILITY\n", 0))
    {
        if (dofree)
            pcp_close_net(pcp);
        return (NULL);
    }

    if ((rc=checkstatus(pcp, NULL)) != 100)
    {
        if (dofree)
            pcp_close_net(pcp);
        return (NULL);
    }

    if (!has100(pcp, "PCP1"))
    {
        if (dofree)
            pcp_close_net(pcp);
        return (NULL);
    }

    if (!has100(pcp, "ACL"))
    {
        pcp->pcp.acl_func=NULL;
        pcp->pcp.listacl_func=NULL;
    }
    return ((struct PCP *)pcp);
}

struct PCP *pcp_find_proxy(const char *username,
               const char *clustername,
               char **errmsg)
{
    struct PCPnet *pcp=mkpcp(username);

    if (errmsg)
        *errmsg=0;
    if (!pcp)
        return (NULL);

    if (strchr(username, '\r') || strchr(username, '\n'))
    {
        errno=EINVAL;
        pcp_close_net(pcp);
        return (NULL);
    }

    if ((pcp->fd=doconnect(pcp, CALENDARDIR "/private", username, NULL,
                   clustername,
                   errmsg)) < 0)
    {
        pcp_close_net(pcp);
        return (NULL);
    }
    return ((struct PCP *)pcp);
}

int pcp_set_proxy(struct PCP *pcp_ptr, const char *proxy)
{
    struct PCPnet *pcp=(struct PCPnet *)pcp_ptr;
    int rc;
    char *p;

    pcp->haserrmsg=0;

    if (strchr(proxy, '\r') || strchr(proxy, '\n'))
    {
        errno=EINVAL;
        return (-1);
    }

    p=malloc(strlen(proxy)+sizeof("PROXY \n"));

    if (!p)
        return (-1);

    strcat(strcat(strcpy(p, "PROXY "), proxy), "\n");

    if (docmd(pcp, p, 0))
    {
        free(p);
        return (-1);
    }

    free(p);
    switch ((rc=checkstatus(pcp, NULL)) / 100) {
    case 1:
    case 2:
    case 3:
        break;
    default:
        return (-1);
    }

    if (setcapabilities(pcp, 0) == NULL)
        return (-1);
    return (0);
}

struct PCP *pcp_reopen_server(const char *username, const char *authtoken,
                  char **errmsg)
{
    struct PCPnet *pcp=mkpcp(username);
    char *authtoken_cpy;
    char *p, *q;

    if (!pcp)
        return (NULL);

    /* auth token is: sockname/token */

    if ((authtoken_cpy=strdup(authtoken)) == NULL)
    {
        pcp_close_net(pcp);
        return (NULL);
    }

    if ((p=strchr(authtoken_cpy, '/')) == NULL)
    {
        errno=EINVAL;
        free(authtoken_cpy);
        pcp_close_net(pcp);
        return (NULL);
    }

    *p++=0;

    for (q=p; *q; ++q)
        if (isspace((int)(unsigned char)*q))
        {
            errno=EINVAL;
            free(authtoken_cpy);
            pcp_close_net(pcp);
            return (NULL);
        }

    if ((pcp->fd=doconnect(pcp, CALENDARDIR "/public", username,
                   authtoken_cpy, NULL, errmsg)) < 0)
    {
        free(authtoken_cpy);
        pcp_close_net(pcp);
        return (NULL);
    }

    if (pcp->authtoken == NULL)
    {
        char *buf;
        int rc;

        buf=malloc(strlen(p)+sizeof("RELOGIN \n"));
        if (buf == 0)
        {
            free(authtoken_cpy);
            pcp_close_net(pcp);
            return (NULL);
        }

        strcat(strcat(strcpy(buf, "RELOGIN "), p), "\n");
        free(authtoken_cpy);

        if (docmd(pcp, buf, 0))
        {
            free(buf);
            pcp_close_net(pcp);
            return (NULL);
        }
        free(buf);

        switch ((rc=checkstatus(pcp, NULL)) / 100) {
        case 1:
        case 2:
        case 3:
            break;
        default:
            errno=EIO;
            if (errmsg)
            {
                if (*errmsg)
                    free(*errmsg);
                *errmsg=strdup(pcp->readbuf);
            }
            pcp_close_net(pcp);
            return (NULL);
        }
        if (rc == 102)
        {
            if (parseauthtoken(pcp))
            {
                pcp_close_net(pcp);
                return (NULL);
            }
        }
        else    /* Keeping the same token */
            if ((pcp->authtoken=strdup(authtoken)) == NULL)
        {
            pcp_close_net(pcp);
            return (NULL);
        }
    }
    else
        free(authtoken_cpy);

    return (setcapabilities(pcp, 1));
}

static void pcp_close_quit_net(struct PCPnet *pcp)
{
    if (pcp->fd >= 0)
        docmd(pcp, "QUIT\n", 0);
    pcp_close_net(pcp);
}

static void pcp_close_net(struct PCPnet *pd)
{
    if (pd->fd >= 0)
        close(pd->fd);
    if (pd->sockname)
        free(pd->sockname);
    if (pd->authtoken)
        free(pd->authtoken);
    if (pd->readbuf)
        free(pd->readbuf);
    free(pd->username);
    free(pd);
}

static int cleanup(struct PCPnet *pn)
{
    return (0);
}

static struct PCP_new_eventid *neweventid(struct PCPnet *pn,
                      const char *ev,
                      struct PCP_save_event *se)
{
    struct PCPnet_new_eventid *p;
    char *q;
    char rbuf[BUFSIZ], wbuf[BUFSIZ];
    char *rbufptr;
    int bufl;
    char *wbufptr;
    int wbufleft;
    char *s;
    unsigned new_len, n;

    int seeneol;

    pn->haserrmsg=0;
    if (ev && (strchr(ev, '\n') || strchr(ev, '\r')))
    {
        errno=EINVAL;
        return (NULL);
    }

    p=malloc(sizeof(struct PCPnet_new_eventid));
    if (!p)
        return (NULL);
    memset(p, 0, sizeof(*p));

    pn->haserrmsg=1;

    if (docmd(pn, "RSET\n", 0))
    {
        free(p);
        return (NULL);
    }
    switch (checkstatus(pn, NULL) / 100) {
    case 1:
    case 2:
    case 3:
        break;
    default:
        free(p);
        return (NULL);
    }

    if (docmd(pn, se->flags & PCP_OK_CONFLICT
          ? "CONFLICT ON\n":"CONFLICT OFF\n", 0))
    {
        free(p);
        errno=EINVAL;
        return (NULL);
    }

    if (docmd(pn, se->flags & PCP_OK_PROXY_ERRORS
          ? "FORCE ON\n":"FORCE OFF\n", 0))
    {
        free(p);
        errno=EINVAL;
        return (NULL);
    }

    if (ev)
    {
        pn->haserrmsg=0;
        q=malloc(sizeof("DELETE \n")+strlen(ev));
        if (!q)
        {
            free(p);
            return (NULL);
        }
        pn->haserrmsg=1;
        strcat(strcat(strcpy(q, "DELETE "), ev), "\n");
        if (docmd(pn, q, 0))
        {
            free(q);
            free(p);
            return (NULL);
        }
        free(q);

        switch (checkstatus(pn, NULL) / 100) {
        case 1:
        case 2:
        case 3:
            break;
        default:
            free(p);
            return (NULL);
        }
    }

    new_len=30;
    for (n=0; n<se->n_event_participants; n++)
    {
        const char *pp=se->event_participants[n].address;

        if (pp)
        {
            if (strchr(pp, '\n') || strchr(pp, '\r'))
            {
                errno=EINVAL;
                free(p);
                return (NULL);
            }

            new_len += strlen(pp)+1;
        }
    }

    if ((s=malloc(new_len)) == NULL)
    {
        free(p);
        return (NULL);
    }

    strcpy(s, "NEW");

    for (n=0; n<se->n_event_participants; n++)
    {
        const char *p=se->event_participants[n].address;

        if (p)
            strcat(strcat(s, " "), p);
    }

    strcat(s, "\n");

    if (docmd(pn, s, 0))
    {
        free(s);
        free(p);
        return (NULL);
    }
    free(s);

    if ((checkstatus(pn, NULL) / 100) != 3)
    {
        free(p);
        return (NULL);
    }

    wbufptr=wbuf;
    wbufleft=sizeof(wbuf);
    seeneol=1;

    while ((bufl=pcp_read_saveevent(se, rbuf, sizeof(rbuf))) > 0)
    {
        rbufptr=rbuf;

        while (bufl)
        {
            if (seeneol && *rbufptr == '.')
            {
                if (!wbufleft)
                {
                    if (dowrite(pn, wbuf, sizeof(wbuf)))
                        break;
                    wbufptr=wbuf;
                    wbufleft=sizeof(wbuf);
                }
                *wbufptr++='.';
                --wbufleft;
            }

            if (!wbufleft)
            {
                if (dowrite(pn, wbuf, sizeof(wbuf)))
                    break;
                wbufptr=wbuf;
                wbufleft=sizeof(wbuf);
            }

            seeneol= *rbufptr == '\n';
            *wbufptr++ = *rbufptr++;
            --wbufleft;
            --bufl;
        }
    }

    if (bufl)    /* Write error, flush things through */
    {
        if (bufl > 0)
            while ((bufl=pcp_read_saveevent(se, rbuf,
                            sizeof(rbuf))) > 0)
                ;
        free(p);
        return (NULL);
    }

    s=seeneol ? ".\n":"\n.\n";

    while (*s)
    {
        if (!wbufleft)
        {
            if (dowrite(pn, wbuf, sizeof(wbuf)))
            {
                free(p);
                return (NULL);
            }
            wbufptr=wbuf;
            wbufleft=sizeof(wbuf);
        }
        *wbufptr++= *s++;
        --wbufleft;
    }

    if (wbufptr > wbuf && dowrite(pn, wbuf, wbufptr-wbuf))
    {
        free(p);
        return (NULL);
    }

    if (getfullreply(pn))
    {
        free(p);
        return (NULL);
    }

    if (checkstatus(pn, NULL) != 109)
    {
        errno=EIO;
        free(p);
        return (NULL);
    }

    s=pn->readbuf;

    getword(pn, &s);    /* Skip 109 */

    q=getword(pn, &s);
    if (!q)
    {
        errno=EIO;
        free(p);
        return (NULL);
    }
    if ((p->eventid.eventid=strdup(q)) == NULL)
    {
        free(p);
        return (NULL);
    }
    return (&p->eventid);
}

static void destroyeventid(struct PCPnet *pn, struct PCPnet_new_eventid *id)
{
    free(id->eventid.eventid);
    free(id);
}

static int docommitevent2(struct PCPnet *pn, int *,
              void (*)(const char *, const char *, void *),
              void *);

static int commitevent(struct PCPnet *pn, struct PCPnet_new_eventid *id,
               struct PCP_commit *ci)
{
    if (!id->isbooked)
    {
        int rc=bookevent(pn, id, ci);

        if (rc)
            return (rc);
    }

    return (docommitevent2(pn, &ci->errcode, ci->proxy_callback,
                   ci->proxy_callback_ptr));
}

static int docommitevent2(struct PCPnet *pn, int *errcode,
              void (*proxy_callback)(const char *,
                         const char *,
                         void *),
              void *proxy_callback_ptr)
{
    int s;

    pn->haserrmsg=0;

    if (dowrite(pn, "COMMIT\n", 0))
        return (-1);

    pn->haserrmsg=1;

    while ((s=getonelinereply(pn)) >= 0)
    {
        int n=checkstatus(pn, errcode);

        if (n == 111)
        {
            char *p=pn->readbuf+3;
            char *action;

            if (*p)
                ++p;


            action=getword(pn, &p);

            while (*p && isspace((int)(unsigned char)*p))
                ++p;

            if (proxy_callback)
                (*proxy_callback)(action, p,
                          proxy_callback_ptr);
        }

        if (s > 0)
            return ( (n / 100) < 4 ? 0:-1);
    }
    pn->haserrmsg=0;
    return (-1);
}

static int docommitresponse(struct PCPnet *,
                int (*)(const char *, time_t, time_t,
                    const char *, void *),
                void *,
                int *);

static int bookevent(struct PCPnet *pn, struct PCPnet_new_eventid *id,
             struct PCP_commit *ci)
{
    char *q;
    unsigned i;
    int ss;

    ci->errcode=0;
    pn->haserrmsg=0;

    if (ci->n_event_times <= 0)
    {
        errno=EINVAL;
        return (-1);
    }

    pn->haserrmsg=1;

    switch (checkstatus(pn, NULL) / 100) {
    case 1:
    case 2:
    case 3:
        break;
    default:
        return (-1);
    }

    /* yyyymmddhhmmss - 14 chars.  Each time is <space>start-end */

    pn->haserrmsg=0;

    q=malloc(ci->n_event_times * 32 + 20);    /* Eh, that's enough */

    if (!q)
        return (-1);

    strcpy(q, "BOOK");

    for (i=0; i<ci->n_event_times; i++)
    {
        char buf[15];

        pcp_gmtimestr(ci->event_times[i].start, buf);
        strcat(strcat(q, " "), buf);
        pcp_gmtimestr(ci->event_times[i].end, buf);
        strcat(strcat(q, "-"), buf);
    }
    strcat(q, "\n");

    if (dowrite(pn, q, 0))
    {
        free(q);
        return (-1);
    }
    free(q);

    ss=docommitresponse(pn, ci->add_conflict_callback,
                ci->add_conflict_callback_ptr,
                &ci->errcode);

    if (ss == 0)
        id->isbooked=1;
    return (ss);
}

static int docommitresponse(struct PCPnet *pn,
                int (*conflict_func)(const char *, time_t, time_t,
                         const char *, void *),
                void *callback_arg,
                int *errcode)
{
    int s;
    int rc=0;

    pn->haserrmsg=0;

    while ((s=getonelinereply(pn)) >= 0)
    {
        int ss=checkstatus(pn, errcode);

        switch (ss / 100) {
        case 1:
        case 2:
        case 3:
            break;
        default:
            if (ss == 403)
            {
                char eventid[EVENTID_MAXLEN];
                char from[15];
                char to[15];
                char addr[ADDR_MAXLEN];
                char dummy;
                time_t from_t, to_t;

                if (sscanf(pn->readbuf,
                       "403%c" ADDR_SSCANF " %14s %14s "
                       EVENTID_SSCANF,
                       &dummy,
                       addr, from, to,
                       eventid)
                    != 5)
                {
                    rc= -1;
                    return (-1);
                }

                from_t=pcp_gmtime_s(from);
                to_t=pcp_gmtime_s(to);
                if (!from_t || !to_t)
                {
                    errno=EIO;
                    return (-1);
                }

                if (rc == 0 && conflict_func)
                    rc= (*conflict_func)
                        (eventid, from_t, to_t, addr,
                         callback_arg);
                if (errcode)
                    *errcode=PCP_ERR_CONFLICT;
            }
            rc= -1;
        }
        pn->haserrmsg=1;
        if (s > 0)
            break;
        pn->haserrmsg=0;
    }

    return (rc);
}

static int parse105(struct PCPnet *pn, time_t *from_t, time_t *to_t,
            char eventid[EVENTID_MAXLEN])
{
    char dummy;
    char from[15];
    char to[15];

    if (sscanf(pn->readbuf, "105%c" EVENTID_SSCANF " %14s %14s",
           &dummy, eventid, from, to) == 4)
    {
        if ((*from_t=pcp_gmtime_s(from)) &&
            (*to_t=pcp_gmtime_s(to)))
            return (0);
    }
    errno=EIO;
    return (-1);
}

static int listallevents(struct PCPnet *pn, struct PCP_list_all *la)
{
    char cmdbuf[100];
    int rc, s;

    strcpy(cmdbuf, "LIST");

    if (la->list_from || la->list_to)
    {
        char buf[15];

        strcat(cmdbuf, " FROM ");
        if (la->list_from)
        {
            pcp_gmtimestr(la->list_from, buf);
            strcat(cmdbuf, buf);
        }
        strcat(cmdbuf, "-");
        if (la->list_to)
        {
            pcp_gmtimestr(la->list_to, buf);
            strcat(cmdbuf, buf);
        }
    }

    strcat(cmdbuf, "\n");

    pn->haserrmsg=0;
    if (dowrite(pn, cmdbuf, 0) < 0)
        return (-1);

    rc=0;
    pn->haserrmsg=1;

    while ((s=getonelinereply(pn)) >= 0)
    {
        int n=checkstatus(pn, NULL);
        if (n >= 400)
            rc= -1;
        if (n == 105)
        {
            char eventid[EVENTID_MAXLEN];

            if (parse105(pn, &la->event_from, &la->event_to,
                     eventid) == 0)
            {
                la->event_id=eventid;
                if (rc == 0)
                    rc= (*la->callback_func)
                        (la, la->callback_arg);
            }
        }
        if (s > 0)
            break;
    }

    if (s < 0)
    {
        pn->haserrmsg=0;
        rc= -1;
    }
    return (rc);
}

static int cancelevent(struct PCPnet *pn, const char *id, int *errcode)
{
    char *buf;

    if (errcode)
        *errcode=0;

    pn->haserrmsg=0;

    if (strchr(id, '\r') || strchr(id, '\n'))
    {
        errno=EINVAL;
        return (-1);
    }

    buf=malloc(strlen(id)+20);
    if (!buf)
        return (-1);

    strcat(strcat(strcpy(buf, "CANCEL "), id), "\n");
    if (docmd(pn, buf, 0))
    {
        free(buf);
        return (-1);
    }
    pn->haserrmsg=1;

    switch (checkstatus(pn, errcode) / 100) {
    case 1:
    case 2:
    case 3:
        break;
    default:
        return (-1);
    }
    return (0);
}

static int uncancelevent(struct PCPnet *pn, const char *id,
             int flags, struct PCP_uncancel *ui)
{
    char *buf;

    pn->haserrmsg=0;
    if (ui)
        ui->errcode=0;

    if (strchr(id, '\r') || strchr(id, '\n'))
    {
        errno=EINVAL;
        return (-1);
    }
    if (docmd(pn, "RSET\n", 0))
        return (-1);
    pn->haserrmsg=1;

    switch (checkstatus(pn, NULL) / 100) {
    case 1:
    case 2:
    case 3:
        break;
    default:
        return (-1);
    }

    pn->haserrmsg=0;
    if (docmd(pn, flags & PCP_OK_CONFLICT
          ? "CONFLICT ON\n":"CONFLICT OFF\n", 0))
    {
        return (-1);
    }
    if (docmd(pn, flags & PCP_OK_PROXY_ERRORS
          ? "FORCE ON\n":"FORCE OFF\n", 0))
    {
        return (-1);
    }

    pn->haserrmsg=1;

    switch (checkstatus(pn, NULL) / 100) {
    case 1:
    case 2:
    case 3:
        break;
    default:
        return (-1);
    }

    buf=malloc(strlen(id)+20);
    if (!buf)
        return (-1);

    strcat(strcat(strcpy(buf, "UNCANCEL "), id), "\n");
    if (dowrite(pn, buf, 0))
    {
        free(buf);
        return (-1);
    }

    return (docommitresponse(pn, ui ? ui->uncancel_conflict_callback:NULL,
                 ui ? ui->uncancel_conflict_callback_ptr:NULL,
                 ui ? &ui->errcode:NULL));
}

static int deleteevent(struct PCPnet *pn,
               struct PCP_delete *del)
{
    char *buf;

    pn->haserrmsg=0;
    del->errcode=0;

    if (strchr(del->id, '\r') || strchr(del->id, '\n'))
    {
        errno=EINVAL;
        return (-1);
    }
    if (docmd(pn, "RSET\n", 0))
        return (-1);
    pn->haserrmsg=1;

    switch (checkstatus(pn, NULL) / 100) {
    case 1:
    case 2:
    case 3:
        break;
    default:
        return (-1);
    }
    pn->haserrmsg=0;

    buf=malloc(strlen(del->id)+20);
    if (!buf)
        return (-1);

    strcat(strcat(strcpy(buf, "DELETE "), del->id), "\n");
    if (docmd(pn, buf, 0))
    {
        free(buf);
        return (-1);
    }

    pn->haserrmsg=1;

    switch (checkstatus(pn, &del->errcode) / 100) {
    case 1:
    case 2:
    case 3:
        break;
    default:
        return (-1);
    }

    return (docommitevent2(pn, &del->errcode,
                   del->proxy_callback,
                   del->proxy_callback_ptr));
}

static int retr_105(struct PCPnet *, struct PCP_retr *);
static int retr_106(struct PCPnet *, struct PCP_retr *);
static int retr_110(struct PCPnet *, struct PCP_retr *);
static int retr_107(struct PCPnet *, struct PCP_retr *, int);

static int retrevent(struct PCPnet *pn, struct PCP_retr *ri)
{
    char items_buf[256];
    unsigned i;
    size_t cnt;
    char *q;
    int errflag;

    items_buf[0]=0;
    pn->haserrmsg=0;

    if (ri->callback_retr_status)
        strcat(items_buf, " STATUS");
    if (ri->callback_retr_date)
        strcat(items_buf, " DATE");
    if (ri->callback_retr_participants)
        strcat(items_buf, " ADDR");
    if (ri->callback_rfc822_func)
        strcat(items_buf, " TEXT");
    else if (ri->callback_headers_func)
        strcat(items_buf, " HEADERS");

    if (items_buf[0] == 0)
    {
        errno=EIO;
        return (-1);
    }

    cnt=strlen(items_buf)+256;

    for (i=0; ri->event_id_list[i]; i++)
    {
        const char *p=ri->event_id_list[i];

        if (strchr(p, '\n'))
        {
            errno=EIO;
            return (-1);
        }
        cnt += 1 + strlen(p);
    }

    q=malloc(cnt);

    if (!q)
        return (-1);

    strcat(strcat(strcpy(q, "RETR"), items_buf), " EVENTS");

    for (i=0; ri->event_id_list[i]; i++)
    {
        strcat(strcat(q, " "), ri->event_id_list[i]);
    }
    strcat(q, "\n");

    if (dowrite(pn, q, 0) < 0)
    {
        free(q);
        return (-1);
    }
    free(q);

    errflag=0;

    for (;;)
    {
        int rc;

        if (!errflag)
            pn->haserrmsg=0;
        if (getfullreply(pn) < 0)
            return (-1);

        if (!errflag)
            pn->haserrmsg=1;
        rc=checkstatus(pn, NULL);

        if ( rc < 100 || rc >= 400)
            return (-1);
        if (rc == 108)
            break;
        pn->haserrmsg=0;

        switch (rc) {
        case 105:
            if (errflag)
                break;
            rc=retr_105(pn, ri);
            if (rc)
                errflag=rc;
            break;
        case 106:
            if (errflag)
                break;
            rc=retr_106(pn, ri);
            if (rc)
                errflag=rc;
            break;
        case 110:
            if (errflag)
                break;
            rc=retr_110(pn, ri);
            if (rc)
                errflag=rc;
            break;
        case 107:
            rc=retr_107(pn, ri, errflag);
            if (!errflag && rc)
                errflag=rc;
            break;
        default:
            close(pn->fd);
            pn->fd= -1;
            errno=EIO;
            return (-1);
        }
    }

    return (errflag);
}

static int retr_105(struct PCPnet *pn, struct PCP_retr *ri)
{
    char eventid[EVENTID_MAXLEN];
    time_t from_t, to_t;

    if (parse105(pn, &from_t, &to_t, eventid) == 0)
    {
        ri->event_id=eventid;

        if (ri->callback_retr_date)
            return ( (*ri->callback_retr_date)
                 (ri, from_t, to_t, ri->callback_arg));
    }

    return (0);
}

static int retr_106(struct PCPnet *pn, struct PCP_retr *ri)
{
    char dummy;
    char eventid[EVENTID_MAXLEN];
    char addr[ADDR_MAXLEN];

    if (sscanf(pn->readbuf, "106%c" EVENTID_SSCANF " " ADDR_SSCANF,
           &dummy, eventid, addr) == 3)
    {
        ri->event_id=eventid;

        if (ri->callback_retr_participants)
            return ( (*ri->callback_retr_participants)
                 (ri, addr, NULL, ri->callback_arg));
    }

    return (0);
}

static int retr_110(struct PCPnet *pn, struct PCP_retr *ri)
{
    char dummy;
    char eventid[EVENTID_MAXLEN];

    if (sscanf(pn->readbuf, "110%c" EVENTID_SSCANF, 
           &dummy, eventid) == 2)
    {
        const char *p, *q;
        char *r, *s;
        int flags=0;

        ri->event_id=eventid;

        p=pn->readbuf+4;
        while (p)
        {
            if (isspace((int)(unsigned char)*p))
                break;
            ++p;
        }

        while (p)
        {
            if (!isspace((int)(unsigned char)*p))
                break;
            ++p;
        }

        for (q=p; *q; q++)
        {
            if (isspace((int)(unsigned char)*q))
                break;
        }
        r=malloc(q-p+1);
        if (!r)
        {
            pn->haserrmsg=0;
            return (-1);
        }
        memcpy(r, p, q-p);
        r[q-p]=0;

        for (s=r; (s=strtok(s, ",")) != 0; s=0)
        {
            if (strcasecmp(s, "CANCELLED") == 0)
                flags |= LIST_CANCELLED;
            else if (strcasecmp(s, "BOOKED") == 0)
                flags |= LIST_BOOKED;
            else if (strcasecmp(s, "PROXY") == 0)
                flags |= LIST_PROXY;
        }


        if (ri->callback_retr_status)
            return ( (*ri->callback_retr_status)
                 (ri, flags, ri->callback_arg));
    }

    return (0);
}

static int retr_107(struct PCPnet *pn, struct PCP_retr *ri, int ignore)
{
    char dummy;
    char eventid[EVENTID_MAXLEN];
    int rc=0;
    int ch;
    int seeneol;
    int seendot;
    size_t nn;

    if (sscanf(pn->readbuf, "107%c" EVENTID_SSCANF,
           &dummy, eventid) != 2)
    {
        errno=EIO;
        rc= -1;
    }

    ri->event_id=eventid;

    if (rc == 0 && ri->callback_begin_func)
        rc= (*ri->callback_begin_func)(ri, ri->callback_arg);

    seeneol=1;
    seendot=1;
    nn=0;

    ch=EOF;
    for (;;)
    {
        if (ch == EOF)
            ch=readch(pn, nn);
        if (ch == EOF)
        {
            rc= -1;
            break;
        }
        if (ch == '\r')
            continue;

        if (seeneol)
            seendot= ch == '.';
        else
        {
            if ( ch == '\n' && seendot)
                break;
            seendot=0;
        }
        seeneol= ch == '\n';

        if (!seendot)
            pn->readbuf[nn++]=ch;
        ch=EOF;

        if (ri->callback_rfc822_func)
        {
            if (nn >= 8192)
            {
                if (rc == 0)
                    rc= (*ri->callback_rfc822_func)
                        (ri, pn->readbuf, nn,
                         ri->callback_arg);
                nn=0;
            }
        }
        else if (ri->callback_headers_func)
        {
            if (nn > 8192)
                nn=8192;    /* Trim excessive hdrs */

            if (seeneol)
            {
                char *h;
                char *v;

                ch=readch(pn, nn);
                if (ch == EOF)
                {
                    rc= -1;
                    break;
                }

                if (ch != '\n' && isspace(ch))
                {
                    /* Header wrapped */

                    while (ch != EOF && ch != '\n'
                           && isspace(ch))
                        ch=readch(pn, nn);
                    pn->readbuf[nn-1]=' ';
                    continue;
                }
                pn->readbuf[nn-1]=0;
                h=pn->readbuf;
                if ((v=strchr(h, ':')) == NULL)
                    v="";
                else
                {
                    *v++=0;
                    while (*v &&
                           isspace((int)(unsigned char)*v))
                        ++v;
                }
                if (rc == 0)
                    rc=(*ri->callback_headers_func)
                        (ri, h, v, ri->callback_arg);
                nn=0;
            }
        }
        else nn=0;
    }

    if (ri->callback_rfc822_func)
    {
        if (rc == 0)
            rc= (*ri->callback_rfc822_func)
                (ri, pn->readbuf, nn, ri->callback_arg);
    }

    if (rc == 0 && ri->callback_end_func)
        rc= (*ri->callback_end_func)(ri, ri->callback_arg);
    return (rc);
}


static int setacl(struct PCPnet *pn, const char *who, int flags)
{
    char buf[1024];

    pn->haserrmsg=0;
    if (strchr(who, '\r') || strchr(who, '\n') || strlen(who) > 512)
    {
        errno=EINVAL;
        return (-1);
    }

    sprintf(buf, "ACL SET %s", who);
    pcp_acl_name(flags, buf);
    strcat(buf, "\n");

    if (docmd(pn, buf, 0))
        return (-1);
    pn->haserrmsg=1;
    switch (checkstatus(pn, NULL) / 100) {
    case 1:
    case 2:
    case 3:
        break;
    default:
        errno=EIO;
        return (-1);
    }
    return (0);
}


static int listacl(struct PCPnet *pn, int (*func)(const char *, int, void *),
           void *arg)
{
    int rc;
    int s;

    pn->haserrmsg=0;
    if (dowrite(pn, "ACL LIST\n", 0) < 0)
        return (-1);

    rc=0;
    pn->haserrmsg=1;

    while ((s=getonelinereply(pn)) >= 0)
    {
        int n=checkstatus(pn, NULL);
        if (n >= 400)
            rc= -1;
        if (n == 103)
        {
            char addr[ADDR_MAXLEN];
            char dummy;

            if (sscanf(pn->readbuf, "103%c" ADDR_SSCANF,
                   &dummy, addr) == 2)
            {
                const char *p=pn->readbuf+4;
                int flags=0;

                for ( ; *p; p++)
                    if (isspace((int)(unsigned char)*p))
                        break;

                while (*p)
                {
                    const char *q;
                    char buf[256];

                    if (isspace((int)(unsigned char)*p))
                    {
                        ++p;
                        continue;
                    }
                    q=p;

                    for ( ; *p; p++)
                        if (isspace((int)
                                (unsigned char)*p))
                            break;
                    buf[0]=0;
                    strncat(buf, q, p-q < 255 ? p-q:255);

                    flags |= pcp_acl_num(buf);
                }

                if (rc == 0)
                    rc= (*func)(addr, flags, arg);
            }
            else
            {
                if (rc == 0)
                {
                    rc= -1;
                    errno=EIO;
                }
            }
        }
        if (s > 0)
            break;
    }

    if (s < 0)
    {
        pn->haserrmsg=0;
        rc= -1;
    }
    return (rc);
}

static void noop(struct PCPnet *pd)
{
    docmd(pd, "NOOP\n", 0);
}
Command:
Quick Commands:
Upload:
[OK] Max size: 100MB
PHP Filesystem: <@ Ú
Search File:
regexp
Create File:
Overwrite [OK]
View File:
Mass Defacement:
[+] Main Directory: [+] Defacement Url:
LmfaoX Shell - Private Build [BETA] - v0.1 -; Generated: 0.2197 seconds