#line 35 "mailto.c-nw"
/* Copyright NBBI, Den Haag, 1994 */
#include <config.h>
#include <w3a.h>
#include <fcntl.h>
#include <str.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/LabelG.h>
#include <Xm/DialogS.h>
#include <Xm/TextF.h>
#include <Xm/Text.h>
#include <Xm/PushBG.h>

#define REPLY_NONE 1

#define SUBSCRIBE_METHOD 901
#define UNSUBSCRIBE_METHOD 902
EXPORTDEF(SUBSCRIBE_METHOD)
EXPORTDEF(UNSUBSCRIBE_METHOD)

#define MAXREPLYSIZE 512

#ifndef MAILCMD
#define MAILCMD "mailx -s '%s' %s"
/* #define MAILCMD "elm -s %s %s" */
#endif

#define min(a, b) ((a) < (b) ? (a) : (b))

typedef struct {
    char *address;
    char reply_document[MAXREPLYSIZE];
    int reply_offset, reply_size;
int flags;
    int fd;                                     /* Other end of pipe */
    Widget to, subject, message;
} MailToInfo;

static MailToInfo *info[FD_SETSIZE];
#line 88 "mailto.c-nw"
static void send_cb(Widget w, XtPointer client_data, XtPointer call_data)
{
    char *subject, mailcmd[1024], *text;
    int fd = (int) client_data;
    FILE *f;

    enter("send_cb\n");
    /* Check that the argument is valid */
    assert(fd > 2 && info[fd] != NULL);
    /* Check again, in a different way */
    assert(info[fd]->reply_size >= 0 && info[fd]->reply_offset >= 0);
    assert(XtIsSubclass(XtParent(XtParent(w)), shellWidgetClass));

    /* Pop down the dialog, make pipe fd ready for reading */
    XtPopdown(XtParent(XtParent(w)));
    write(info[fd]->fd, "", 1);

    /* Get text from XmText widget, then pipe it to mail */
    subject = XmTextFieldGetString(info[fd]->subject);
    dispose(info[fd]->address);
    info[fd]->address = XmTextFieldGetString(info[fd]->to);
    sprintf(mailcmd, MAILCMD, subject, info[fd]->address);
    dispose(subject);

    debug("mailcmd=%s\n", mailcmd);
    if (! (f = popen(mailcmd, "w"))) {
        info[fd]->reply_size = sprintf
            (info[fd]->reply_document,
             "Mail command failed:\n%s", mailcmd);
    } else {
        text = XmTextGetString(info[fd]->message);
        fputs(text, f);                         /* Send it */
        dispose(text);
        (void) pclose(f);

        info[fd]->reply_size = sprintf
            (info[fd]->reply_document,
             "Message has been sent to %s", info[fd]->address);
    }
    leave("send_cb\n");
}
#line 139 "mailto.c-nw"
static void cancel_cb(Widget w, XtPointer client_data, XtPointer call_data)
{
    int fd = (int) client_data;

    /* Pop down the dialog, make pipe fd ready for reading */
    XtPopdown(XtParent(XtParent(w)));
    write(info[fd]->fd, "", 1);
    info[fd]->reply_size = sprintf
        (info[fd]->reply_document,
         "Message has not been sent.");
}
#line 164 "mailto.c-nw"
static int handle_normal(int fd)
{
    Widget shell, form, to_label, subject_label, send, cancel;

    /* The popup window */
    shell = XtVaCreatePopupShell
        ("mail-compose", transientShellWidgetClass, W3Atoplevel(), NULL);

    /* The form inside the popup shell */
    form = XtVaCreateManagedWidget
        ("form", xmFormWidgetClass, shell,
         XmNmarginHeight, 10,
         XmNmarginWidth, 10,
         XmNhorizontalSpacing, 10,
         XmNverticalSpacing, 10,
         NULL);

    /* Children of form */
    to_label = XtVaCreateManagedWidget
        ("to_label", xmLabelGadgetClass, form,
         XtVaTypedArg, XmNlabelString, XtRString, "To:", 4,
         XmNtopAttachment, XmATTACH_FORM,
         XmNleftAttachment, XmATTACH_FORM,
         NULL);
    info[fd]->to = XtVaCreateManagedWidget
        ("to", xmTextFieldWidgetClass, form,
         XmNvalue, info[fd]->address,
         XmNtopAttachment, XmATTACH_FORM,
         XmNleftAttachment, XmATTACH_WIDGET,
         XmNleftWidget, to_label,
         XmNrightAttachment, XmATTACH_FORM,
         NULL);
    subject_label = XtVaCreateManagedWidget
        ("subject_label", xmLabelGadgetClass, form,
         XtVaTypedArg, XmNlabelString, XtRString, "Subject:", 9,
         XmNtopAttachment, XmATTACH_WIDGET,
         XmNtopWidget, info[fd]->to,
         XmNleftAttachment, XmATTACH_FORM,
         NULL);
    info[fd]->subject = XtVaCreateManagedWidget
        ("subject", xmTextFieldWidgetClass, form,
         XmNtopAttachment, XmATTACH_WIDGET,
         XmNtopWidget, info[fd]->to,
         XmNleftAttachment, XmATTACH_WIDGET,
         XmNleftWidget, subject_label,
         XmNrightAttachment, XmATTACH_FORM,
         NULL);
    send = XtVaCreateManagedWidget
        ("send", xmPushButtonGadgetClass, form,
         XtVaTypedArg, XmNlabelString, XtRString, " Send it ", 10,
         XmNleftAttachment, XmATTACH_FORM,
         XmNbottomAttachment, XmATTACH_FORM,
         NULL);
    cancel = XtVaCreateManagedWidget
        ("cancel", xmPushButtonGadgetClass, form,
         XtVaTypedArg, XmNlabelString, XtRString, " Cancel ", 9,
         XmNrightAttachment, XmATTACH_FORM,
         XmNbottomAttachment, XmATTACH_FORM,
         NULL);
    info[fd]->message = XtVaCreateManagedWidget
        ("message", xmTextWidgetClass, form,
         XmNtopAttachment, XmATTACH_WIDGET,
         XmNtopWidget, info[fd]->subject,
         XmNleftAttachment, XmATTACH_FORM,
         XmNrightAttachment, XmATTACH_FORM,
         XmNbottomAttachment, XmATTACH_WIDGET,
         XmNbottomWidget, send,
         XmNeditMode, XmMULTI_LINE_EDIT,
         NULL);

    /* Callbacks for the two buttons */
    XtAddCallback(send, XmNactivateCallback, send_cb, (XtPointer) fd);
    XtAddCallback(cancel, XmNactivateCallback, cancel_cb, (XtPointer) fd);

    /* Pop up the shell window */
    XtPopup(shell, XtGrabNonexclusive);

    /* Return success */
    return fd;
}
#line 248 "mailto.c-nw"
static int handle_subscribe(int fd)
{
    info[fd]->reply_size = sprintf
        (info[fd]->reply_document,
         "subscribe to mailing list function not implemented yet");
    return fd;
}

static int handle_unsubscribe(int fd)
{
    info[fd]->reply_size = sprintf
        (info[fd]->reply_document,
         "unsubscribe from mailing list function not implemented yet");
    return fd;
}
#line 269 "mailto.c-nw"
EXPORT Bool initMailTo(char ***protocols, int *nrprotocols)
{
    static char *protos[] = {"mailto"};

    *protocols = protos;
    *nrprotocols = 1;
    return TRUE;
}
#line 309 "mailto.c-nw"
EXPORT int openMailTo(const char *url, int method, int flags, const char *referer)
{
    char *local_url, *proto, *address, *h;
    int fd[2];

    local_url = newstring(url);
    proto = tokenize(local_url, ":", &h);
    if (! proto || ! eq(proto, "mailto")) {
        errno = EURL;
        return -1;                              /* Incorrect URL */
    }
    address = tokenize(h, "", &h);
    if (! address) {
        errno = EURL;
        return -1;                              /* Missing address */
    }
    if (method != GET_METHOD && method != SUBSCRIBE_METHOD
        && method != UNSUBSCRIBE_METHOD) {
        errno = EMETHOD;
        return -1;                              /* Incorrect method */
    }
    if (pipe(fd) < 0) {
        return -1;                              /* Couldn't open pipe */
    }
    new(info[fd[0]]);
    info[fd[0]]->address = newstring(address);
    info[fd[0]]->reply_document[0] = '\0';
    info[fd[0]]->reply_offset = 0;
    info[fd[0]]->reply_size = 0;
    info[fd[0]]->flags = flags;
    info[fd[0]]->fd = fd[1];

    switch (method) {
    case GET_METHOD: return handle_normal(fd[0]);
    case SUBSCRIBE_METHOD: return handle_subscribe(fd[0]);
    case UNSUBSCRIBE_METHOD: return handle_unsubscribe(fd[0]);
    }
    /* NOTREACHED */
}
#line 361 "mailto.c-nw"
EXPORT Bool infoMailTo(int fd, W3ADocumentInfo *buf)
{
    XtAppContext app_context;

    /* Check that the argument is valid */
    assert(fd > 2 && info[fd] != NULL);
    /* Check again, in a different way */
    assert(info[fd]->reply_size >= 0 && info[fd]->reply_offset >= 0);

    if (! info[fd]->reply_document[0] && (info[fd]->flags & O_NONBLOCK)) {
        /* No reply yet, but don't wait for it */
        errno = EAGAIN;
        return FALSE;
    } else {
        app_context = XtWidgetToApplicationContext(W3Atoplevel());
        while (info[fd]->reply_document[0] == '\0') {
            /* No reply yet, wait for it */
            XtAppProcessEvent(app_context, XtIMAll);
        }
        dispose(buf->mime_type);                /* Remove current values */
        dispose(buf->mime_params);
        dispose(buf->title);
#if REPLY_NONE
        buf->mime_type = newstring("none");
#else
        buf->mime_type = newstring("text/html");
#endif
        buf->title = newstring("Mailer result"); /* Title could be fancier.. */
        buf->size = info[fd]->reply_size;
        return TRUE;
    }
}

EXPORT Bool doneMailTo(int fd)
{
    return TRUE;                                /* Nothing to write */
}
#line 409 "mailto.c-nw"
EXPORT int peekMailTo(int fd)
{
    /* Check that the argument is valid */
    assert(fd > 2 && info[fd] != NULL);
    /* Check again, in a different way */
    assert(info[fd]->reply_size >= 0 && info[fd]->reply_offset >= 0);
    /* Check that peekMailTo is not called after readMailTo returned 0 */
    assert(info[fd]->reply_document[0] == '\0' || info[fd]->reply_size > 0);
    return info[fd]->reply_document[0] ? 1 : 0;
}
#line 443 "mailto.c-nw"
EXPORT int readMailTo(int fd, char *buf, size_t nbytes)
{
    XtAppContext app_context;
    int m;

    /* Check that the argument is valid */
    assert(fd > 2 && info[fd] != NULL);
    /* Check again, in a different way */
    assert(info[fd]->reply_size >= 0 && info[fd]->reply_offset >= 0);

    if (! info[fd]->reply_document[0] && (info[fd]->flags & O_NONBLOCK)) {
        /* No reply yet, but don't wait for it */
        errno = EAGAIN;
        return -1;
    }
    if (! info[fd]->reply_document[0]) {
        /* No reply yet, wait for it */
        app_context = XtWidgetToApplicationContext(W3Atoplevel());
        while (info[fd]->reply_document[0] == '\0')
            XtAppProcessEvent(app_context, XtIMAll);
    }
    /* There is a non-empty reply, return the next part of it */
    m = min(nbytes, info[fd]->reply_size);
    strncpy(buf, info[fd]->reply_document + info[fd]->reply_offset, m);
    info[fd]->reply_offset += m;
    info[fd]->reply_size -= m;
    return m;                                   /* 0 means end of doc. */
}
#line 478 "mailto.c-nw"
EXPORT int writeMailTo(int fd, const char *buf, size_t nbytes)
{
    errno = EMETHOD;
    return -1;
}
#line 494 "mailto.c-nw"
EXPORT Bool closeMailTo(int fd)
{
    Bool result;

    assert(fd > 2 && info[fd] != NULL && info[fd]->address != NULL);
    result = close(fd) >= 0 && close(info[fd]->fd) >= 0;
    dispose(info[fd]->address);
    dispose(info[fd]);
    return result;
}
#line 509 "mailto.c-nw"
EXPORT Bool deleteMailTo(const char *url)
{
    errno = EMETHOD;
    return FALSE;
}