diff options
author | Alain Magloire <alainm@gnu.org> | 2004-06-13 02:52:13 +0000 |
---|---|---|
committer | Alain Magloire <alainm@gnu.org> | 2004-06-13 02:52:13 +0000 |
commit | f50de094ab26e6e81438d056e31236e776e4dc65 (patch) | |
tree | 887ac1f9f92ce476449c77fe974f3c16aae648b8 | |
parent | fcba09634592afea9d4f8e0f05d6baabbd8acd23 (diff) | |
download | mailutils-f50de094ab26e6e81438d056e31236e776e4dc65.tar.gz mailutils-f50de094ab26e6e81438d056e31236e776e4dc65.tar.bz2 |
nntp_carrier.c nntp_connect.c nntp_create.c nntp_debug.c
nntp_destroy.c nntp_disconnect.c nntp_readline.c
nntp_response.c nntp_sendline.c nntp_stream.c nntp_timeout.c
framework for NNTP support
-rw-r--r-- | mailbox/nntp/nntp_carrier.c | 55 | ||||
-rw-r--r-- | mailbox/nntp/nntp_connect.c | 81 | ||||
-rw-r--r-- | mailbox/nntp/nntp_create.c | 72 | ||||
-rw-r--r-- | mailbox/nntp/nntp_debug.c | 53 | ||||
-rw-r--r-- | mailbox/nntp/nntp_destroy.c | 49 | ||||
-rw-r--r-- | mailbox/nntp/nntp_disconnect.c | 47 | ||||
-rw-r--r-- | mailbox/nntp/nntp_readline.c | 191 | ||||
-rw-r--r-- | mailbox/nntp/nntp_response.c | 72 | ||||
-rw-r--r-- | mailbox/nntp/nntp_sendline.c | 120 | ||||
-rw-r--r-- | mailbox/nntp/nntp_stream.c | 145 | ||||
-rw-r--r-- | mailbox/nntp/nntp_timeout.c | 48 |
11 files changed, 933 insertions, 0 deletions
diff --git a/mailbox/nntp/nntp_carrier.c b/mailbox/nntp/nntp_carrier.c new file mode 100644 index 000000000..42ba82a1f --- /dev/null +++ b/mailbox/nntp/nntp_carrier.c @@ -0,0 +1,55 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2004 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <mailutils/sys/nntp.h> + +int +mu_nntp_set_carrier (mu_nntp_t nntp, stream_t carrier) +{ + /* Sanity checks. */ + if (nntp == NULL) + return EINVAL; + + if (nntp->carrier) + { + /* Close any old carrier. */ + mu_nntp_disconnect (nntp); + stream_destroy (&nntp->carrier, nntp); + } + nntp->carrier = carrier; + return 0; +} + +int +mu_nntp_get_carrier (mu_nntp_t nntp, stream_t *pcarrier) +{ + /* Sanity checks. */ + if (nntp == NULL) + return EINVAL; + if (pcarrier == NULL) + return MU_ERR_OUT_PTR_NULL; + + *pcarrier = nntp->carrier; + return 0; +} diff --git a/mailbox/nntp/nntp_connect.c b/mailbox/nntp/nntp_connect.c new file mode 100644 index 000000000..3e17fe095 --- /dev/null +++ b/mailbox/nntp/nntp_connect.c @@ -0,0 +1,81 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2004 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <sys/time.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <mailutils/sys/nntp.h> + +/* Open the connection to the server. */ +int +mu_nntp_connect (mu_nntp_t nntp) +{ + int status; + + /* Sanity checks. */ + if (nntp == NULL) + return EINVAL; + + /* A networking stack. */ + if (nntp->carrier == NULL) + return EINVAL; + + /* Enter the pop state machine, and boogy: AUTHORISATION State. */ + switch (nntp->state) + { + default: + /* FALLTHROUGH */ + /* If nntp was in an error state going through here should clear it. */ + + case MU_NNTP_NO_STATE: + status = mu_nntp_disconnect (nntp); + MU_NNTP_CHECK_EAGAIN (nntp, status); + nntp->state = MU_NNTP_CONNECT; + + case MU_NNTP_CONNECT: + /* Establish the connection. */ + status = stream_open (nntp->carrier); + MU_NNTP_CHECK_EAGAIN (nntp, status); + nntp->acknowledge = 0; + nntp->state = MU_NNTP_GREETINGS; + + case MU_NNTP_GREETINGS: + /* Get the greetings. */ + { + size_t len = 0; + char *right, *left; + status = mu_nntp_response (nntp, NULL, 0, &len); + MU_NNTP_CHECK_EAGAIN (nntp, status); + mu_nntp_debug_ack (nntp); + if (nntp->ack.buf[0] == '2') + { + stream_close (nntp->carrier); + nntp->state = MU_NNTP_NO_STATE; + return EACCES; + } + nntp->state = MU_NNTP_NO_STATE; + } + } /* End AUTHORISATION state. */ + + return status; +} diff --git a/mailbox/nntp/nntp_create.c b/mailbox/nntp/nntp_create.c new file mode 100644 index 000000000..5e2d85850 --- /dev/null +++ b/mailbox/nntp/nntp_create.c @@ -0,0 +1,72 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2004 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <errno.h> +#include <mailutils/errno.h> +#include <mailutils/sys/nntp.h> + +/* Initialise a mu_nntp_t handle. */ + +int +mu_nntp_create (mu_nntp_t *pnntp) +{ + mu_nntp_t nntp; + + /* Sanity check. */ + if (pnntp == NULL) + return EINVAL; + + nntp = calloc (1, sizeof *nntp); + if (nntp == NULL) + return ENOMEM; + + /* Reserve space for the ack(nowledgement) response. + According to RFC 977: The maximum length of the first line of a + command response (including the initial greeting) is unchanged at + 512 octets (including the terminating CRLF). */ + nntp->ack.len = 512; + nntp->ack.buf = calloc (nntp->ack.len, 1); + if (nntp->ack.buf == NULL) + { + mu_nntp_destroy (&nntp); + return ENOMEM; + } + nntp->ack.ptr = nntp->ack.buf; + + /* Reserve space for the data response/content. + RFC 977 recommands 255, but we grow it as needed. */ + nntp->io.len = 255; + nntp->io.buf = calloc (nntp->io.len, 1); + if (nntp->io.buf == NULL) + { + mu_nntp_destroy (&nntp); + return ENOMEM; + } + nntp->io.ptr = nntp->io.buf; + + nntp->state = MU_NNTP_NO_STATE; /* Init with no state. */ + nntp->timeout = (10 * 60) * 100; /* The default Timeout is 10 minutes. */ + nntp->acknowledge = 0; /* No Ack received. */ + + *pnntp = nntp; + return 0; /* Okdoke. */ +} diff --git a/mailbox/nntp/nntp_debug.c b/mailbox/nntp/nntp_debug.c new file mode 100644 index 000000000..e18664fb1 --- /dev/null +++ b/mailbox/nntp/nntp_debug.c @@ -0,0 +1,53 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2004 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <errno.h> +#include <mailutils/sys/nntp.h> + +int +mu_nntp_set_debug (mu_nntp_t nntp, mu_debug_t debug) +{ + if (nntp == NULL) + return EINVAL; + if (nntp->debug) + mu_debug_destroy (&nntp->debug, NULL); + nntp->debug = debug; + return 0; +} + +int +mu_nntp_debug_cmd (mu_nntp_t nntp) +{ + if (nntp->debug) + mu_debug_print(nntp->debug, MU_DEBUG_PROT, "%s", nntp->io.buf); + return 0; +} + +int +mu_nntp_debug_ack (mu_nntp_t nntp) +{ + if (nntp->debug) + { + mu_debug_print (nntp->debug, MU_DEBUG_PROT, "%s\n", nntp->ack.buf); + } + return 0; +} diff --git a/mailbox/nntp/nntp_destroy.c b/mailbox/nntp/nntp_destroy.c new file mode 100644 index 000000000..a70df8168 --- /dev/null +++ b/mailbox/nntp/nntp_destroy.c @@ -0,0 +1,49 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2004 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <mailutils/errno.h> +#include <mailutils/sys/nntp.h> + +void +mu_nntp_destroy (mu_nntp_t *pnntp) +{ + if (pnntp && *pnntp) + { + mu_nntp_t nntp = *pnntp; + + /* Free the response buffer. */ + if (nntp->ack.buf) + free (nntp->ack.buf); + + /* Free the io buffer. */ + if (nntp->io.buf) + free (nntp->io.buf); + + /* Release the carrier. */ + if (nntp->carrier) + stream_destroy (&nntp->carrier, nntp); + + free (nntp); + + *pnntp = NULL; + } +} diff --git a/mailbox/nntp/nntp_disconnect.c b/mailbox/nntp/nntp_disconnect.c new file mode 100644 index 000000000..00b0ff7a1 --- /dev/null +++ b/mailbox/nntp/nntp_disconnect.c @@ -0,0 +1,47 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2004 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <mailutils/sys/nntp.h> + +int +mu_nntp_disconnect (mu_nntp_t nntp) +{ + /* Sanity checks. */ + if (nntp == NULL) + return EINVAL; + + /* We can keep some of the fields, if they decide to nntp_connect() again but + clear the states. */ + nntp->state = MU_NNTP_NO_STATE; + nntp->acknowledge = 0; + + /* Clear the buffers. */ + memset (nntp->io.buf, '\0', nntp->io.len); + nntp->io.ptr = nntp->io.buf; + memset (nntp->ack.buf, '\0', nntp->ack.len); + nntp->ack.ptr = nntp->ack.buf; + + /* Close the stream. */ + return stream_close (nntp->carrier); +} diff --git a/mailbox/nntp/nntp_readline.c b/mailbox/nntp/nntp_readline.c new file mode 100644 index 000000000..ba2125ef5 --- /dev/null +++ b/mailbox/nntp/nntp_readline.c @@ -0,0 +1,191 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2004 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#include <errno.h> +#include <mailutils/sys/nntp.h> +#include <mailutils/error.h> + +int +mu_nntp_carrier_is_ready (stream_t carrier, int flag, int timeout) +{ + struct timeval tv, *tvp = NULL; + int wflags = flag; + int status; + + if (timeout >= 0) + { + tv.tv_sec = timeout / 100; + tv.tv_usec = (timeout % 1000) * 1000; + tvp = &tv; + } + status = stream_wait (carrier, &wflags, tvp); + if (status) + return 0; /* FIXME: provide a way to return error code! */ + return wflags & flag; +} + +/* Read a complete line from the nntp server. Transform CRLF to LF, remove + the stuff byte termination octet ".", put a null in the buffer + when done. And Do a select() (stream_is_readready()) for the timeout. */ +static int +mu_nntp_getline (mu_nntp_t nntp) +{ + size_t n = 0; + size_t total = nntp->io.ptr - nntp->io.buf; + int status = 0; + + /* Must get a full line before bailing out. */ + do + { + /* Timeout with select(), note that we have to reset select() + since on linux tv is modified when error. */ + if (nntp->timeout) + { + int ready = mu_nntp_carrier_is_ready (nntp->carrier, + MU_STREAM_READY_RD, + nntp->timeout); + if (ready == 0) + return ETIMEDOUT; + } + + status = stream_sequential_readline (nntp->carrier, nntp->io.buf + total, nntp->io.len - total, &n); + if (status != 0) + return status; + + /* The server went away: It maybe a timeout and some nntp server + does not send the -ERR. Consider this like an error. */ + if (n == 0) + return EIO; + + total += n; + nntp->io.nl = memchr (nntp->io.buf, '\n', total); + if (nntp->io.nl == NULL) /* Do we have a full line. */ + { + /* Allocate a bigger buffer ? */ + if (total >= nntp->io.len - 1) + { + nntp->io.len *= 2; + nntp->io.buf = realloc (nntp->io.buf, nntp->io.len + 1); + if (nntp->io.buf == NULL) + return ENOMEM; + } + } + nntp->io.ptr = nntp->io.buf + total; + } + while (nntp->io.nl == NULL); /* Bail only if we have a complete line. */ + + /* When examining a multi-line response, the client checks to see if the + line begins with the termination octet "."(DOT). If yes and if octets + other than CRLF follow, the first octet of the line (the termination + octet) is stripped away. */ + if (total >= 3 && nntp->io.buf[0] == '.') + { + if (nntp->io.buf[1] != '\r' && nntp->io.buf[2] != '\n') + { + memmove (nntp->io.buf, nntp->io.buf + 1, total - 1); + nntp->io.ptr--; + nntp->io.nl--; + } + /* And if CRLF immediately follows the termination character, then + the response from the NNTP server is ended and the line containing + ".CRLF" is not considered part of the multi-line response. */ + else if (nntp->io.buf[1] == '\r' && nntp->io.buf[2] == '\n') + { + nntp->io.buf[0] = '\0'; + nntp->io.ptr = nntp->io.buf; + nntp->io.nl = NULL; + } + } + /* \r\n --> \n\0, conversion. */ + if (nntp->io.nl > nntp->io.buf) + { + *(nntp->io.nl - 1) = '\n'; + *(nntp->io.nl) = '\0'; + nntp->io.ptr = nntp->io.nl; + } + return status; +} + +/* Call nntp_getline() for the dirty work, and consume i.e. put + in the user buffer only buflen. If buflen == 0 or buffer == NULL + nothing is consume, the data is save for another call to nntp_readline() + with a buffer != NULL. + */ +int +mu_nntp_readline (mu_nntp_t nntp, char *buffer, size_t buflen, size_t *pnread) +{ + size_t nread = 0; + size_t n = 0; + int status = 0; + + /* Do we need to fill up? Yes if no NL or the buffer is empty. */ + if (nntp->carrier && (nntp->io.nl == NULL || nntp->io.ptr == nntp->io.buf)) + { + status = mu_nntp_getline (nntp); + if (status != 0) + return status; + } + + /* How much we can copy ? */ + n = nntp->io.ptr - nntp->io.buf; + + /* Consume the line? */ + if (buffer && buflen) + { + buflen--; /* For the null. */ + if (buflen) + { + int nleft = buflen - n; + /* We got more then requested. */ + if (nleft < 0) + { + size_t sentinel; + nread = buflen; + sentinel = nntp->io.ptr - (nntp->io.buf + nread); + memcpy (buffer, nntp->io.buf, nread); + memmove (nntp->io.buf, nntp->io.buf + nread, sentinel); + nntp->io.ptr = nntp->io.buf + sentinel; + } + else + { + /* Drain our buffer. */; + nread = n; + memcpy (buffer, nntp->io.buf, nread); + nntp->io.ptr = nntp->io.buf; + /* Clear of all residue. */ + memset (nntp->io.buf, '\0', nntp->io.len); + } + } + buffer[nread] = '\0'; + } + else + nread = n; + + if (pnread) + *pnread = nread; + return status; +} diff --git a/mailbox/nntp/nntp_response.c b/mailbox/nntp/nntp_response.c new file mode 100644 index 000000000..a943a8743 --- /dev/null +++ b/mailbox/nntp/nntp_response.c @@ -0,0 +1,72 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2004 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <errno.h> +#include <mailutils/sys/nntp.h> + +/* If we did not grap the ack already, call nntp_readline() but handle + Nonblocking also. */ +int +mu_nntp_response (mu_nntp_t nntp, char *buffer, size_t buflen, size_t *pnread) +{ + size_t n = 0; + int status = 0; + + if (nntp == NULL) + return EINVAL; + + if (!nntp->acknowledge) + { + size_t len = nntp->ack.len - (nntp->ack.ptr - nntp->ack.buf); + status = mu_nntp_readline (nntp, nntp->ack.ptr, len, &n); + nntp->ack.ptr += n; + if (status == 0) + { + len = nntp->ack.ptr - nntp->ack.buf; + if (len && nntp->ack.buf[len - 1] == '\n') + nntp->ack.buf[len - 1] = '\0'; + nntp->acknowledge = 1; /* Flag that we have the ack. */ + nntp->ack.ptr = nntp->ack.buf; + } + else + { + /* Provide them with an error. */ + const char *econ = "500 NNTP IO ERROR"; + n = strlen (econ); + strcpy (nntp->ack.buf, econ); + } + } + else + n = strlen (nntp->ack.buf); + + if (buffer) + { + buflen--; /* Leave space for the NULL. */ + n = (buflen < n) ? buflen : n; + memcpy (buffer, nntp->ack.buf, n); + buffer[n] = '\0'; + } + + if (pnread) + *pnread = n; + return status; +} diff --git a/mailbox/nntp/nntp_sendline.c b/mailbox/nntp/nntp_sendline.c new file mode 100644 index 000000000..e2a3cb09a --- /dev/null +++ b/mailbox/nntp/nntp_sendline.c @@ -0,0 +1,120 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2004 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <string.h> + +#include <errno.h> +#include <mailutils/sys/nntp.h> + +/* A socket may write less then expected but stream.c:stream_write() will + always try to send the entire buffer unless an error is reported. We have + to cope with nonblocking, it is done by keeping track with the nntp->ptr + pointer if the write failed we keep track and restart where we left. */ +int +mu_nntp_send (mu_nntp_t nntp) +{ + int status = 0; + if (nntp->carrier && (nntp->io.ptr > nntp->io.buf)) + { + size_t n = 0; + size_t len = nntp->io.ptr - nntp->io.buf; + + /* Timeout with select(), note that we have to reset select() + since on linux tv is modified when error. */ + if (nntp->timeout) + { + int ready = mu_nntp_carrier_is_ready (nntp->carrier, + MU_STREAM_READY_WR, + nntp->timeout); + if (ready == 0) + return ETIMEDOUT; + } + + status = stream_write (nntp->carrier, nntp->io.buf, len, 0, &n); + if (n) + { + /* Consume what we sent. */ + memmove (nntp->io.buf, nntp->io.buf + n, len - n); + nntp->io.ptr -= n; + } + } + else + nntp->io.ptr = nntp->io.buf; + return status; +} + +/* According to RFC 2449: The maximum length of a command is increased from + 47 characters (4 character command, single space, 40 character argument, + CRLF) to 255 octets, including the terminating CRLF. But we are flexible + on this and realloc() as needed. NOTE: The terminated CRLF is not + included. */ +int +mu_nntp_writeline (mu_nntp_t nntp, const char *format, ...) +{ + int len; + va_list ap; + int done = 1; + + va_start(ap, format); + /* C99 says that a conforming implementation of snprintf () should + return the number of char that would have been call but many old + GNU/Linux && BSD implementations return -1 on error. Worse, + QnX/Neutrino actually does not put the terminal null char. So + let's try to cope. */ + do + { + len = vsnprintf (nntp->io.buf, nntp->io.len - 1, format, ap); + if (len < 0 || len >= (int)nntp->io.len + || !memchr (nntp->io.buf, '\0', len + 1)) + { + nntp->io.len *= 2; + nntp->io.buf = realloc (nntp->io.buf, nntp->io.len); + if (nntp->io.buf == NULL) + return ENOMEM; + done = 0; + } + else + done = 1; + } + while (!done); + va_end(ap); + nntp->io.ptr = nntp->io.buf + len; + return 0; +} + +int +mu_nntp_sendline (mu_nntp_t nntp, const char *line) +{ + if (line) + { + int status = mu_nntp_writeline (nntp, line); + if (status) + return status; + } + return mu_nntp_send (nntp); +} diff --git a/mailbox/nntp/nntp_stream.c b/mailbox/nntp/nntp_stream.c new file mode 100644 index 000000000..a76f91743 --- /dev/null +++ b/mailbox/nntp/nntp_stream.c @@ -0,0 +1,145 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <mailutils/sys/nntp.h> + +/* Implementation of the stream for TOP and RETR. */ +struct mu_nntp_stream +{ + mu_nntp_t nntp; + int done; +}; + +static void +mu_nntp_stream_destroy (stream_t stream) +{ + struct mu_nntp_stream *nntp_stream = stream_get_owner (stream); + if (nntp_stream) + { + free (nntp_stream); + } +} + +static int +mu_nntp_stream_read (stream_t stream, char *buf, size_t buflen, off_t offset, size_t *pn) +{ + struct mu_nntp_stream *nntp_stream = stream_get_owner (stream); + size_t n = 0; + int status = 0; + char *p = buf; + + (void)offset; + if (nntp_stream) + { + if (!nntp_stream->done) + { + do + { + size_t nread = 0; + + /* The nntp_readline () function will always read one less to + be able to null terminate the buffer, this will cause + serious grief for stream_read() where it is legitimate to + have a buffer of 1 char. So we must catch it here. */ + if (buflen == 1) + { + char buffer[2]; + *buffer = '\0'; + status = mu_nntp_readline (nntp_stream->nntp, buffer, 2, &nread); + *p = *buffer; + } + else + status = mu_nntp_readline (nntp_stream->nntp, p, buflen, &nread); + + if (status != 0) + break; + if (nread == 0) + { + nntp_stream->nntp->state = MU_NNTP_NO_STATE; + nntp_stream->done = 1; + break; + } + n += nread; + buflen -= nread; + p += nread; + } + while (buflen > 0); + } + } + if (pn) + *pn = n; + return status; +} + +static int +mu_nntp_stream_readline (stream_t stream, char *buf, size_t buflen, off_t offset, size_t *pn) +{ + struct mu_nntp_stream *nntp_stream = stream_get_owner (stream); + size_t n = 0; + int status = 0; + + (void)offset; + if (nntp_stream) + { + if (!nntp_stream->done) + { + status = mu_nntp_readline (nntp_stream->nntp, buf, buflen, &n); + if (n == 0) + { + nntp_stream->nntp->state = MU_NNTP_NO_STATE; + nntp_stream->done = 1; + } + } + } + if (pn) + *pn = n; + return status; +} + +int +mu_nntp_stream_create (mu_nntp_t nntp, stream_t *pstream) +{ + struct mu_nntp_stream *nntp_stream; + int status; + + nntp_stream = malloc (sizeof *nntp_stream); + if (nntp_stream == NULL) + return ENOMEM; + + nntp_stream->nntp = nntp; + nntp_stream->done = 0; + + status = stream_create (pstream, MU_STREAM_READ | MU_STREAM_NO_CLOSE | MU_STREAM_NO_CHECK, nntp_stream); + if (status != 0) + { + free (nntp_stream); + return status; + } + + stream_set_read (*pstream, mu_nntp_stream_read, nntp_stream); + stream_set_readline (*pstream, mu_nntp_stream_readline, nntp_stream); + stream_set_destroy (*pstream, mu_nntp_stream_destroy, nntp_stream); + + return 0; +} diff --git a/mailbox/nntp/nntp_timeout.c b/mailbox/nntp/nntp_timeout.c new file mode 100644 index 000000000..1e6ea5b34 --- /dev/null +++ b/mailbox/nntp/nntp_timeout.c @@ -0,0 +1,48 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2004 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <errno.h> +#include <mailutils/sys/nntp.h> + +int +mu_nntp_set_timeout (mu_nntp_t nntp, int timeout) +{ + /* Sanity checks. */ + if (nntp == NULL) + return EINVAL; + + nntp->timeout = timeout; + return 0; +} + +int +mu_nntp_get_timeout (mu_nntp_t nntp, int *ptimeout) +{ + /* Sanity checks. */ + if (nntp == NULL) + return EINVAL; + if (ptimeout == NULL) + return MU_ERR_OUT_PTR_NULL; + + *ptimeout = nntp->timeout; + return 0; +} |