feat: first commit
This commit is contained in:
commit
bc96196ffd
9 changed files with 535 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
config.h
|
||||
**/*.swp
|
||||
**/*~
|
||||
**/*.o
|
||||
**/*.core
|
||||
sis
|
||||
24
LICENSE
Normal file
24
LICENSE
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2024, Lorenzo Torres
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the <organization> nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
52
Makefile
Normal file
52
Makefile
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# sis - simple imap server
|
||||
# See LICENSE file for copyright and license details.
|
||||
|
||||
include config.mk
|
||||
|
||||
SRC = sis.c imap.c
|
||||
HDR = config.def.h
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
all: options sis
|
||||
|
||||
options:
|
||||
@echo sis build options:
|
||||
@echo "CFLAGS = ${CFLAGS}"
|
||||
@echo "LDFLAGS = ${LDFLAGS}"
|
||||
@echo "CC = ${CC}"
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $<
|
||||
|
||||
${OBJ}: config.h config.mk
|
||||
|
||||
config.h:
|
||||
cp config.def.h $@
|
||||
|
||||
sis: ${OBJ}
|
||||
${CC} -o $@ ${OBJ} ${LDFLAGS}
|
||||
|
||||
clean:
|
||||
rm -f sis ${OBJ} sis-${VERSION}.tar.gz
|
||||
|
||||
dist: clean
|
||||
mkdir -p sis-${VERSION}
|
||||
cp -R LICENSE Makefile README config.mk\
|
||||
sis.1 ${HDR} ${SRC} sis-${VERSION}
|
||||
tar -cf sis-${VERSION}.tar sis-${VERSION}
|
||||
gzip sis-${VERSION}.tar
|
||||
rm -rf sis-${VERSION}
|
||||
|
||||
install: all
|
||||
mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
cp -f sis ${DESTDIR}${PREFIX}/bin
|
||||
chmod 755 ${DESTDIR}${PREFIX}/bin/sis
|
||||
mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||
sed "s/VERSION/${VERSION}/g" < sis.1 > ${DESTDIR}${MANPREFIX}/man1/sis.1
|
||||
chmod 644 ${DESTDIR}${MANPREFIX}/man1/sis.1
|
||||
|
||||
uninstall:
|
||||
rm -f ${DESTDIR}${PREFIX}/bin/dwm\
|
||||
${DESTDIR}${MANPREFIX}/man1/dwm.1
|
||||
|
||||
.PHONY: all options clean dist install uninstall
|
||||
33
README
Normal file
33
README
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
sis - simple imap server
|
||||
============================
|
||||
sis is an IMAP server, following the unix philosophy,
|
||||
trying to be as small as possible while providing
|
||||
a reliable service.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
In order to build sis you need... a computer
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
Edit config.mk to match your local setup (sis is installed into
|
||||
the /usr/local namespace by default).
|
||||
|
||||
Afterwards enter the following command to build and install sis (if
|
||||
necessary as root):
|
||||
|
||||
make clean install
|
||||
|
||||
|
||||
Running sis
|
||||
-----------
|
||||
By default, sis runs in daemon mode, if you want to avoid detaching use the -d option
|
||||
sis -d
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
The configuration of sis is done by creating a custom config.h
|
||||
and (re)compiling the source code.
|
||||
22
config.def.h
Normal file
22
config.def.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
/* network */
|
||||
#define IMAP_PORT 143
|
||||
#define IMAPS_PORT 993
|
||||
/*-
|
||||
* Maximum number of connected clients,
|
||||
* NOTE: each one of these is a currently
|
||||
* connected client! Unless your server
|
||||
* has to manage a lot of accounts you
|
||||
* should be good with the default value.
|
||||
*/
|
||||
#define MAX_CLIENTS 30
|
||||
/*-
|
||||
* Maximum size for the command buffer.
|
||||
* IMAP sends plain text commands, so
|
||||
* the default value can receive up to
|
||||
* 8000 characters long commands.
|
||||
* It should be enough but feel free to
|
||||
* modify this.
|
||||
*/
|
||||
#define CMD_MAX_SIZE 8000
|
||||
27
config.mk
Normal file
27
config.mk
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# sis version
|
||||
VERSION = 0.1
|
||||
|
||||
# Customize below to fit your system
|
||||
|
||||
# paths
|
||||
PREFIX = /usr
|
||||
MANPREFIX = ${PREFIX}/share/man
|
||||
|
||||
# OpenBSD (uncomment)
|
||||
#MANPREFIX = ${PREFIX}/man
|
||||
|
||||
# includes and libs
|
||||
INCS = -I.
|
||||
LIBS =
|
||||
# flags
|
||||
CPPFLAGS = -DVERSION=\"${VERSION}\"
|
||||
CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
|
||||
#CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS}
|
||||
LDFLAGS = ${LIBS}
|
||||
|
||||
# Solaris
|
||||
#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
|
||||
#LDFLAGS = ${LIBS}
|
||||
|
||||
# compiler and linker
|
||||
CC = cc
|
||||
239
imap.c
Normal file
239
imap.c
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
/*-
|
||||
* Copyright (c) 2024, Lorenzo Torres
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <config.h>
|
||||
#include <imap.h>
|
||||
|
||||
uint8_t imap_init(uint8_t daemon, imap_t *instance)
|
||||
{
|
||||
imap_t imap;
|
||||
|
||||
/* Create a new socket using IPv4 protocol */
|
||||
if ((imap.socket = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socker");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bzero(&imap.addr, sizeof(struct sockaddr_in));
|
||||
|
||||
imap.addr.sin_family = AF_INET;
|
||||
/* From config.h */
|
||||
imap.addr.sin_port = htons(IMAP_PORT);
|
||||
|
||||
if (INADDR_ANY) {
|
||||
imap.addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
|
||||
/* Bind the socket to the specified address */
|
||||
if ((bind(imap.socket, (struct sockaddr *)&imap.addr, sizeof(imap.addr)) < 0)) {
|
||||
perror("bind");
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* If daemon mode is activated, detach */
|
||||
if (daemon) {
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
perror("fork");
|
||||
return 3;
|
||||
break;
|
||||
default:
|
||||
close(imap.socket);
|
||||
free(instance);
|
||||
exit(0);
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(instance, &imap, sizeof(imap));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int imap_get_max_fd(client_list *list, int master)
|
||||
{
|
||||
int max_fd = 0;
|
||||
client_list *node = list;
|
||||
|
||||
while (node != NULL) {
|
||||
if (max_fd < node->socket) {
|
||||
max_fd = node->socket;
|
||||
}
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return max_fd > master ? max_fd : master;
|
||||
}
|
||||
|
||||
client_list *imap_add_client(client_list *list, int sock)
|
||||
{
|
||||
client_list *node = (client_list *) malloc(sizeof(client_list));
|
||||
node->socket = sock;
|
||||
node->next = list;
|
||||
node->prev = NULL;
|
||||
if (list != NULL) {
|
||||
list->prev = node;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
client_list *imap_remove_client(client_list *list, client_list *node)
|
||||
{
|
||||
if (node->next != NULL) {
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
|
||||
if (node->prev != NULL) {
|
||||
node->prev->next = node->next;
|
||||
}
|
||||
|
||||
close(node->socket);
|
||||
|
||||
if (node == list) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
client_list *imap_remove_sock(client_list *list, int sock)
|
||||
{
|
||||
client_list *node = list;
|
||||
|
||||
while (node != NULL && node->socket != sock) {
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
if (node != NULL) {
|
||||
imap_remove_client(list, node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void imap_start(imap_t *instance)
|
||||
{
|
||||
int activity, max_fd, connection;
|
||||
size_t bytes_read;
|
||||
char buf[CMD_MAX_SIZE];
|
||||
/* List of all the file descriptors (sockets) being used. */
|
||||
fd_set fds;
|
||||
instance->clients = NULL;
|
||||
client_list *node = instance->clients;
|
||||
client_list *tmp = instance->clients;
|
||||
|
||||
listen(instance->socket, BACKLOG);
|
||||
syslog(LOG_INFO, "Listening on %d.", IMAP_PORT);
|
||||
|
||||
for (;;) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(instance->socket, &fds);
|
||||
node = instance->clients;
|
||||
|
||||
while (node != NULL) {
|
||||
FD_SET(node->socket, &fds);
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
max_fd = imap_get_max_fd(instance->clients, instance->socket);
|
||||
activity = select(max_fd + 1, &fds, NULL, NULL, NULL);
|
||||
|
||||
if ((activity < 0) && (errno!=EINTR)) {
|
||||
perror("select");
|
||||
}
|
||||
|
||||
/* New connection. */
|
||||
if (FD_ISSET(instance->socket, &fds)) {
|
||||
if ((connection = accept(instance->socket, NULL, NULL)) < 0) {
|
||||
perror("accept");
|
||||
syslog(LOG_ERR, "Connection failed.");
|
||||
imap_close(instance);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
instance->clients = imap_add_client(instance->clients, connection);
|
||||
syslog(LOG_INFO, "Connection enstablished.");
|
||||
FD_SET(connection, &fds);
|
||||
}
|
||||
|
||||
node = instance->clients;
|
||||
tmp = node;
|
||||
while (node != NULL) {
|
||||
connection = node->socket;
|
||||
tmp = node->next;
|
||||
|
||||
if (FD_ISSET(connection, &fds)) {
|
||||
/* Error occured. */
|
||||
if ((bytes_read = read(connection, buf, CMD_MAX_SIZE)) < 0) {
|
||||
perror("recv");
|
||||
instance->clients = imap_remove_client(instance->clients, node);
|
||||
free(node);
|
||||
FD_CLR(connection, &fds);
|
||||
syslog(LOG_ERR, "Failed to receive data.");
|
||||
/* Somebody disconnected */
|
||||
} else if (bytes_read == 0) {
|
||||
instance->clients = imap_remove_client(instance->clients, node);
|
||||
free(node);
|
||||
FD_CLR(connection, &fds);
|
||||
syslog(LOG_INFO, "Connection closed.");
|
||||
} else {
|
||||
buf[bytes_read] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
node = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imap_close(imap_t *instance)
|
||||
{
|
||||
client_list *node = instance->clients;
|
||||
client_list *tmp = node;
|
||||
while (node != NULL) {
|
||||
close(node->socket);
|
||||
tmp = node->next;
|
||||
free(node);
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
close(instance->socket);
|
||||
free(instance);
|
||||
}
|
||||
64
imap.h
Normal file
64
imap.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*-
|
||||
* Copyright (c) 2024, Lorenzo Torres
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef IMAP_H
|
||||
#define IMAP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define BACKLOG 4
|
||||
|
||||
typedef struct _client_list {
|
||||
int32_t socket;
|
||||
struct _client_list *next;
|
||||
struct _client_list *prev;
|
||||
} client_list;
|
||||
|
||||
|
||||
typedef struct imap {
|
||||
int32_t socket;
|
||||
client_list *clients;
|
||||
struct sockaddr_in addr;
|
||||
} imap_t;
|
||||
|
||||
/* Create a new imap_t instance and initialize the server. */
|
||||
uint8_t imap_init(uint8_t daemon, imap_t *instance);
|
||||
/* Start the IMAP server. */
|
||||
void imap_start(imap_t *instance);
|
||||
/* Close all connections and free the allocated memory. */
|
||||
void imap_close(imap_t *instance);
|
||||
/* Add client to client list */
|
||||
client_list *imap_add_client(client_list *list, int sock);
|
||||
/* Close connection with client */
|
||||
client_list *imap_remove_client(client_list *list, client_list *node);
|
||||
client_list *imap_remove_sock(client_list *list, int sock);
|
||||
/* Get the higher file descriptor in the client list */
|
||||
int imap_get_max_fd(client_list *list, int master);
|
||||
|
||||
#endif /* ifndef IMAP_H */
|
||||
68
sis.c
Normal file
68
sis.c
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*-
|
||||
* Copyright (c) 2024, Lorenzo Torres
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <signal.h>
|
||||
#include <syslog.h>
|
||||
#include <imap.h>
|
||||
|
||||
static imap_t *instance;
|
||||
|
||||
void int_handler(int sig)
|
||||
{
|
||||
if (instance != NULL) {
|
||||
imap_close(instance);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
signal(SIGINT, int_handler);
|
||||
|
||||
openlog("sis", LOG_PID, LOG_MAIL);
|
||||
syslog(LOG_INFO, "Starting sis %s.", VERSION);
|
||||
|
||||
int status = 0;
|
||||
instance = (imap_t *) malloc(sizeof(imap_t));
|
||||
|
||||
if ((status = imap_init(0, instance)) != 0) {
|
||||
perror("imap_init");
|
||||
goto ret;
|
||||
}
|
||||
|
||||
imap_start(instance);
|
||||
|
||||
ret:
|
||||
if (instance != NULL) {
|
||||
imap_close(instance);
|
||||
}
|
||||
|
||||
closelog();
|
||||
return status;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue