Files
archived-lcd4linux/mail2.c
reinelt 546476ef7e [lcd4linux @ 2003-10-05 17:58:50 by reinelt]
libtool junk; copyright messages cleaned up

git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@253 3ae390bd-cb1e-0410-b409-cd5a39f66f1f
2003-10-05 17:58:50 +00:00

513 lines
11 KiB
C

/* $Id: mail2.c,v 1.9 2003/10/05 17:58:50 reinelt Exp $
*
* mail: pop3, imap, news functions
*
* Copyright 2001 Leopold Tötsch <lt@toetsch.at>
*
* This file is part of LCD4Linux.
*
* LCD4Linux is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* LCD4Linux 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
* $Log: mail2.c,v $
* Revision 1.9 2003/10/05 17:58:50 reinelt
* libtool junk; copyright messages cleaned up
*
* Revision 1.8 2003/02/22 07:53:10 reinelt
* cfg_get(key,defval)
*
* Revision 1.7 2002/12/05 19:23:01 reinelt
* fixed undefined operations found by gcc3
*
* Revision 1.6 2001/09/12 06:17:22 reinelt
* *** empty log message ***
*
* Revision 1.5 2001/09/12 05:58:16 reinelt
* fixed bug in mail2.c
*
* Revision 1.4 2001/03/16 09:28:08 ltoetsch
* bugfixes
*
* Revision 1.3 2001/03/15 14:25:05 ltoetsch
* added unread/total news
*
* Revision 1.2 2001/03/15 11:10:53 ltoetsch
* added quit/logout to pop/imap
*
* Revision 1.1 2001/03/14 13:19:29 ltoetsch
* Added pop3/imap4 mail support
*
*
* Exported Functions:
*
* int Mail_pop_imap_news(char *mbox, int *total_mails, int *unseen);
* returns -1 on error, 0 on success
*
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <malloc.h>
#include <errno.h>
#include "debug.h"
#include "cfg.h"
#include "socket.h"
#define PROTO_UNKNOWN -1
#define PROTO_POP3 110
#define PROTO_NNTP 119
#define PROTO_IMAP4 143
/*
* parse_proto()
*
* parse a MailboxN entry in 's' as
*
* proto:[user[:pass]@]machine[:port][/dir]
*
* 's' get's destroyed
* returns 0 on success, -1 on error
*
*/
static int parse_proto(char *s, int *proto, char **user, char **pass,
char **machine, int *port, char **dir)
{
struct
{
char *prefix;
int proto;
}
protos[] =
{
{ "pop3:", PROTO_POP3 },
{ "nntp:", PROTO_NNTP },
{ "imap4:", PROTO_IMAP4 },
};
int i;
char *p, *q;
static char empty[] = "";
static char INBOX[] = "INBOX";
*proto = *port = PROTO_UNKNOWN;
for (i=0; i< sizeof(protos)/sizeof(protos[0]); i++)
{
if (memcmp(s, protos[i].prefix, strlen(protos[i].prefix)) == 0)
{
*proto = *port = protos[i].proto;
break;
}
}
if (*proto == PROTO_UNKNOWN)
return -1;
p = s + strlen(protos[i].prefix);
/*
* this might fail if user or pass contains a '/'
*
*/
if ((q = strchr(p, '/')) != NULL)
{
/* /dir */
*dir = q + 1;
*q = '\0';
}
else
*dir = empty;
if ((q = strchr(p, '@')) != NULL)
{
/* user, pass is present */
*machine = q + 1;
*q = '\0';
*user = p;
if ((q = strchr(p, ':')) != NULL)
{
/* user[:pass] */
*q = '\0';
*pass = q+1;
}
else
*pass = empty;
}
else
{
*machine = p;
*user = *pass = empty;
}
if ((q = strchr(*machine, ':')) != NULL)
{
/* machine[:pass] */
*q = '\0';
*port = atoi(q+1);
if (*port <= 0 || *port >= 0xffff)
return -1;
}
if (!**machine)
return -1;
if (*proto == PROTO_POP3 && **dir)
return -1;
if (*proto == PROTO_IMAP4 && !**dir)
*dir = INBOX;
return 0;
}
/* write buffer, compare with match */
#define BUFLEN 256
static int wr_rd(int fd, char *buf, char *match,
char *err, char *machine, int port)
{
int n;
n = write_socket(fd, buf);
if (n <= 0)
{
error("Couldn't write to %s:%d (%s)", machine, port, strerror(errno));
close(fd);
return -1;
}
n = read_socket_match(fd, buf, BUFLEN-1, match);
if (n <= 0)
{
error("%s %s:%d (%s)", err, machine, port, strerror(errno));
close(fd);
return -1;
}
return n;
}
static int check_nntp(char *user, char *pass, char *machine,
int port, char *dir, int *total, int *unseen)
{
int fd;
int n;
char buf[BUFLEN];
char line[BUFLEN];
FILE *fp;
int groups;
int err;
int totg, unsg;
int first;
*total = 0;
*unseen = 0;
strcpy(buf, cfg_get("Newsrc",".newsrc"));
if (*buf == 0 || ((fp = fopen(buf, "r")) == NULL)) {
error("Couldn't open .newsrc-file '%s'", buf);
return -1;
}
fd = open_socket(machine, port);
if (fd < 0)
{
error("Couldn't connect to %s:%d (%s)", machine, port, strerror(errno));
fclose(fp);
return -1;
}
n = read_socket_match(fd, buf, BUFLEN-1, "20"); /* server ready */
if (n <= 0) {
error("Server doesn't respond %s:%d (%s)", machine, port, strerror(errno));
close(fd);
return -1;
}
/* do auth if necessary, this is NOT TESTED */
if (*user) {
sprintf(buf, "AUTHINFO USER %s\r\n", user);
if (wr_rd(fd, buf, "381", "No AUTH required?", machine, port) <= 0)
return -1;
if (*pass)
{
sprintf(buf, "AUTHINFO PASS %s\r\n", pass);
if (wr_rd(fd, buf, "281", "Wrong PASS?", machine, port) <= 0)
return -1;
}
}
// Fixme: this is badbadbadbad
sleep(2); /* wait for newsserver to read groupinfo */
groups = 0;
err = 0;
totg = unsg = 0; /* total, unseen */
while (fgets(line, sizeof(line)-1, fp) && err < 5) {
char group[256];
char *p;
int smin, smax, lmin, lmax;
if (sscanf(line, "%255[^:]:", group) != 1) {
error("Couldn't read group in '%s'", line);
err++;
continue;
}
if ((p=strchr(group,':')) != NULL)
*p='\0';
/* check dir if it matches group */
if (*dir && strcmp(dir, group))
continue;
sprintf(buf, "GROUP %s\r\n", group);
if (wr_rd(fd, buf, "211", "Wrong Group", machine, port) <= 0) {
err++;
continue;
}
/* answer 211 total smin smax group: */
sscanf(buf, "211 %*d %d %d", &smin, &smax);
debug("nntp: %s: smin=%d smax=%d", group, smin, smax);
totg += smax-smin-1;
p = strchr(line, ':');
p++;
first = 1;
while (1) {
lmin = strtol(p, &p, 10);
if (*p == '-')
lmax = strtol(p+1, &p, 10);
else
lmax=lmin;
debug("nntp: %s: lmin=%d lmax=%d", group, lmin, lmax);
if (smax >= lmax) { /* server has more articles */
if (first)
unsg += smax - lmax;
else
unsg -= lmax-lmin+1;
first = 0;
}
else /* local has higher article ??? */
break;
if (*p == ',')
p++;
else
break;
}
} /* while fp */
fclose(fp);
strcpy(buf, "QUIT\r\n");
wr_rd(fd, buf, "2", "Quit", machine, port);
close(fd);
*unseen = unsg;
*total = totg;
return 0;
}
static int check_imap4(char *user, char *pass, char *machine,
int port, char *dir, int *total, int *unseen)
{
int fd = open_socket(machine, port);
int n;
char buf[BUFLEN];
char *p;
*total=0;
*unseen = 0;
if (fd < 0)
{
error("Couldn't connect to %s:%d (%s)", machine, port, strerror(errno));
return -1;
}
n = read_socket_match(fd, buf, BUFLEN-1, "* OK");
if (n <= 0) {
error("Server doesn't respond %s:%d (%s)", machine, port, strerror(errno));
close(fd);
return -1;
}
sprintf(buf, ". LOGIN %s %s\r\n", user, pass);
if (wr_rd(fd, buf, ". OK", "Wrong User/PASS?", machine, port) <= 0)
return -1;
sprintf(buf, ". STATUS %s (MESSAGES UNSEEN)\r\n", dir);
if (wr_rd(fd, buf, "*", "Wrong dir?", machine, port) <= 0)
return -1;
if ((p = strstr(buf, "MESSAGES")) != NULL)
sscanf(p, "%*s %d", total);
else {
error("Server doesn't provide MESSAGES (%s)", machine, port, strerror(errno));
close(fd);
return -1;
}
if ((p = strstr(buf, "UNSEEN")) != NULL)
sscanf(p, "%*s %d", unseen);
else {
error("Server doesn't provide UNSEEN (%s)", machine, port, strerror(errno));
close(fd);
return -1;
}
strcpy(buf,". LOGOUT\r\n");
wr_rd(fd, buf, "", "LOGOUT", machine, port);
close(fd);
return 0;
}
static int check_pop3(char *user, char *pass, char *machine,
int port, int *total, int *unseen)
{
int fd = open_socket(machine, port);
int n;
char buf[BUFLEN];
*total=0;
*unseen=0;
if (fd < 0)
{
error("Couldn't connect to %s:%d (%s)", machine, port, strerror(errno));
return -1;
}
n = read_socket_match(fd, buf, BUFLEN-1, "+OK");
if (n <= 0) {
error("Server doesn't respond %s:%d (%s)", machine, port, strerror(errno));
close(fd);
return -1;
}
if (*user)
{
sprintf(buf, "USER %s\r\n", user);
if (wr_rd(fd, buf, "+OK", "Wrong USER?", machine, port) <= 0)
return -1;
}
if (*pass)
{
sprintf(buf, "PASS %s\r\n", pass);
if (wr_rd(fd, buf, "+OK", "Wrong PASS?", machine, port) <= 0)
return -1;
}
sprintf(buf, "STAT\r\n");
if (wr_rd(fd, buf, "+OK", "Wrong STAT answer?", machine, port) <= 0)
return -1;
sscanf(buf, "+OK %d", total);
if (*total) {
sprintf(buf, "LAST\r\n");
if (wr_rd(fd, buf, "+OK", "Wrong LAST answer?", machine, port) <= 0)
return -1;
sscanf(buf, "+OK %d", unseen);
*unseen = *total - *unseen;
}
strcpy(buf, "QUIT\r\n");
wr_rd(fd, buf, "+OK", "Quit", machine, port);
close(fd);
return 0;
}
int Mail_pop_imap_news(char *s, int *total, int *unseen)
{
int proto, port, ret;
char *user, *pass, *machine, *dir, *ds;
ds = strdup(s);
if (ds == NULL)
{
error("Out of mem");
return -1;
}
ret = parse_proto(ds, &proto, &user, &pass,
&machine, &port, &dir) ;
if (ret < 0)
error("Not a pop3/imap4 mailbox");
else
ret = (proto == PROTO_POP3) ?
check_pop3(user, pass, machine, port, total, unseen) :
(proto == PROTO_NNTP) ?
check_nntp(user, pass, machine, port, dir, total, unseen) :
check_imap4(user, pass, machine, port, dir, total, unseen);
free(ds);
return ret;
}
#ifdef STANDALONE
/*
* test parse_proto with some garbage
*
*/
int foreground = 1;
int debugging = 3;
/*
* for STANDALONE tests, disable Text driver and
*
* cc -DSTANDALONE mail2.c socket.c debug.c -g -Wall -o mail2
*
*/
#ifdef CHECK_PARSER
static int test(char *s)
{
int ret;
int proto, port;
char *user, *pass, *machine, *dir, *ds;
ds = strdup(s);
ret = parse_proto(ds, &proto, &user, &pass,
&machine, &port, &dir) ;
printf("parse_proto(%s) ret=%d\n", s, ret);
if (!ret)
printf(
"\tproto='%d'\n"
"\tuser='%s'\n"
"\tpass='%s'\n"
"\tmachine='%s'\n"
"\tport='%d'\n"
"\tdir='%s'\n",
proto,user,pass,machine,port,dir);
free(ds);
return ret;
}
#endif
int main(int argc, char *argv[])
{
#ifdef CHECK_PARSER
int i, ret;
/* proto:[user[:pass]@]machine[:port][/dir] */
char *t[] =
{
"pop3:sepp:Geheim@Rechner:123",
"pop3:sepp@Rechner",
"pop3:Rechner:123",
"imap4:sepp:Geheim@Rechner/dir@/:pfad",
"imap4:sepp:Geheim@Rechner",
"imap4sepp:Geheim@Rechner/dir@/:pfad",
"imap4:sepp:Geheim/Rechner/dir@/:pfad",
"pop3:sepp@:",
0
};
ret = 0;
if (argc > 1)
ret |= test(argv[1]);
else
for (i = 0; t[i]; i++)
ret |= test(t[i]);
return ret;
# else
int total = -1, unseen = -1;
char *mbx = "imap4:user:pass@server/folder/file";
int ret = Mail_pop_imap(mbx, &total, &unseen);
printf("ret = %d, total = %d unseen = %d\n", ret, total, unseen);
return ret;
# endif
}
#endif