Commit 2c6536c4 2c6536c4c90629d2f7bb5ae9fc301fcddd0261a3 by Sean 'Shaleh' Perry

added imap daemon

1 parent 6bb43b09
1999-10-11 Sean 'Shaleh' Perry <shaleh@debian.org>
* added my imap code -- PLEASE DO NOT TOUCH
1999-10-10 Jeff Bailey <jbailey@cr499794-a.crdva1.bc.wave.home.com>
* THANKS: New file
......
#include "capability.h"
STATUS imap_capability(Command *command) {
if( command->args )
return BAD;
fprintf(output, "* CAPABILITY IMAP4rev1\r\n");
return OK;
}
#ifndef _MY_IMAP_CAPABILITY
#define _MY_IMAP_CAPABILITY
#include "imap.h"
STATUS imap_capability(Command *command);
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "command.h"
Command* parse_command(char *string) {
size_t len, tmp;
Command *command;
if( string == NULL )
return NULL;
command = malloc(sizeof(Command));
memset(command, '\0', sizeof(Command));
len = strcspn(string, " ");
if( len > 0 ) {
tmp = strcspn(string, "\r\n");
string[tmp] = '\0';
strncpy(command->tag, string, len > 15 ? 15 : len);
} else {
strcpy(command->tag, "gibberish");
return command;
}
tmp = len;
++tmp; /* skip space char */
len = strcspn(string + tmp, " ");
if( len > 0 )
strncpy(command->cmd, string + tmp, len > 15 ? 15 : len);
else {
strcpy(command->cmd, "gibberish");
return command;
}
/* args is the rest of the string */
command->args = string + len + tmp + 1;
if( command->args[0] == '\0' ) /* no args */
command->args = NULL;
return command;
}
void free_command(Command *command) {
free(command);
}
#ifndef _MY_IMAP_COMMAND
#define _MY_IMAP_COMMAND
#include "imap_types.h"
Command *parse_command(char *string);
void free_command(Command *command);
#endif
#ifndef _MY_IMAP
#define _MY_IMAP
#include <stdio.h>
#include <syslog.h>
#include "imap_types.h"
FILE *input;
FILE *output;
/* current server state */
STATES state;
#endif
#ifndef _MY_IMAP_COMMANDS
#define _MY_IMAP_COMMANDS
#include "capability.h"
#include "login.h"
#include "logout.h"
#include "noop.h"
#endif
#ifndef _MY_IMAP_TYPES
#define _MY_IMAP_TYPES
/* possible server states */
enum _STATES {NON_AUTH, AUTH, SELECTED, LOGOUT};
/* imap command status codes */
enum _STATUS {BAD, NO, OK};
typedef enum _STATES STATES;
typedef enum _STATUS STATUS;
typedef struct _Command {
char tag[16];
char cmd[16];
char *args;
} Command;
#endif
#define _XOPEN_SOURCE
#include <unistd.h>
#include <ctype.h>
#include <pwd.h>
#include <shadow.h>
#include <string.h>
#include <sys/types.h>
#include "login.h"
STATUS imap_login(Command *command) {
char user[256];
char *pass;
struct passwd *pw;
struct spwd *shadow;
size_t len;
if( state != NON_AUTH )
return BAD;
if( command->args == NULL )
return BAD;
len = strcspn(command->args, " ");
if( len == 0 || len > 255 )
return BAD;
memset(user, '\0', 256);
strncpy(user, command->args, len);
pass = command->args + len;
++pass; /* skip the space */
if( isspace(pass[0]) )
return BAD;
pw = getpwnam(user);
if ( pw == NULL ) {
syslog(LOG_WARNING, "invalid user: %s\n", user);
return NO;
}
if( strcmp(pw->pw_passwd, crypt(pass, pw->pw_passwd)) ) {
shadow = getspnam(user);
if( shadow == NULL ) {
syslog(LOG_WARNING, "invalid user: %s\n", user);
return NO;
}
if( strcmp(shadow->sp_pwdp, crypt(pass, shadow->sp_pwdp)) ) {
syslog(LOG_WARNING, "invalid user: %s\n", user);
return NO;
}
}
memset(pass, '\0', sizeof(pass)); /* paranoia */
state = AUTH;
syslog(LOG_INFO, "user: %s, logged in\n", user);
return OK;
}
#ifndef _MY_IMAP_LOGIN
#define _MY_IMAP_LOGIN
#include "imap.h"
STATUS imap_login(Command *command);
#endif
#include "logout.h"
STATUS imap_logout(Command *command) {
if( command->args )
return BAD;
/* finish everything */
fprintf(output, "* BYE IMAP4rev1 terminating connection\r\n");
#ifdef STATISTICS
statistics();
#endif
state = LOGOUT;
return OK;
}
#ifndef _MY_IMAP_LOGOUT
#define _MY_IMAP_LOGOUT
#include "imap.h"
STATUS imap_logout(Command *command);
#endif
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "imap.h"
#include "imap_commands.h"
#include "command.h"
#include "readline.h"
static void init(void);
static int mainloop(void);
static void cleanup(void);
static void greeting(void);
static STATUS action(Command *command);
/* state the server is in */
STATES state = NON_AUTH;
FILE *input = NULL;
FILE *output = NULL;
/* output strings, maps STATUS to strings */
static char *status_word[3] = {"BAD", "NO", "OK"};
static char *status_code[3] = {"invalid", "failed", "completed"};
int main(int argc, char *argv[]) {
input = stdin;
output = stdout;
init();
greeting();
mainloop();
cleanup();
fclose(input);
fclose(output);
return 0;
}
static void init(void) {
struct group *gr;
gr = getgrnam("mail");
if( gr == NULL )
exit(-1);
if( setgid(gr->gr_gid) == -1 )
exit(-1);
openlog("GNU IMAP4", LOG_PID, LOG_MAIL);
if( output == stdout )
setvbuf(output, NULL, _IOLBF, 0);
}
static void cleanup(void) {
closelog();
}
static void greeting(void) {
fprintf(output, "* OK IMAP4rev1 Service Ready\r\n");
}
static int mainloop(void) {
char *client_string;
Command *command;
STATUS status;
while( (client_string = read_a_line(input)) != NULL ) {
command = parse_command(client_string);
status = action(command);
fprintf(output, "%s %s %s %s\r\n", command->tag, status_word[status],
command->cmd, status_code[status]);
free_command(command);
free(client_string);
if( state == LOGOUT ) /* all done, let's go */
break;
}
return 1;
}
STATUS action(Command *command) {
if( strcasecmp(command->cmd, "capability") == 0 ) {
return imap_capability(command);
}
else if( strcasecmp(command->cmd, "noop") == 0 ) {
return imap_noop(command);
}
else if( strcasecmp(command->cmd, "logout") == 0 ) {
return imap_logout(command);
}
else if( strcasecmp(command->cmd, "login") == 0 ) {
return imap_login(command);
}
return BAD;
}
#include "noop.h"
STATUS imap_noop(Command *command) {
if( command->args )
return BAD;
fprintf(output, "* OK XSTATE %d\r\n", state);
return OK;
}
#ifndef _MY_IMAP_NOOP
#define _MY_IMAP_NOOP
#include "imap.h"
STATUS imap_noop(Command *command);
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef COUNT
#define COUNT 128 /* safe, middle of the road value */
#endif
/**
* reads a single line from *stream
* max line length is max size of size_t
*
* PRE: stream is an open FILE stream
* POST: returns an allocated string containing the line read, or errno is set
*
* note, user must free the returned string
**/
char *read_a_line(FILE *stream) {
char *line = NULL;
size_t buffsize = 0; /* counter of alloc'ed space */
if( feof(stream) ) { /* sent a bum stream */
errno = EINVAL;
return NULL;
}
do {
if ((line = realloc(line, buffsize + (sizeof(char) * COUNT))) == NULL) {
errno = ENOMEM;
return NULL;
}
if( fgets(line + (buffsize ? buffsize - 1 : 0),COUNT,stream) == NULL ) {
if( buffsize == 0 ) {
errno = EINVAL;
return NULL; /* eof w/ nothing read */
}
break; /* read a line w/o a newline char */
}
buffsize += COUNT;
} while( (strchr(line, '\n')) == NULL );
return line;
}
#ifndef _MY_read_a_line__
#define _MY_read_a_line__
char* read_a_line(FILE *stream);
#endif