Compare commits

...

No commits in common. "master" and "gh-pages" have entirely different histories.

15 changed files with 93 additions and 620 deletions

24
LICENSE
View File

@ -1,24 +0,0 @@
Copyright (c) 2009, R. Tyler Ballance <tyler@monkeypox.org>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* 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 R. Tyler Ballance ''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 R. Tyler Ballance 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.

View File

@ -1,50 +0,0 @@
# Standard definitions
CC ?= gcc
TAR ?= tar
RM ?= -rm
CFLAGS := -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=22 -ggdb `pkg-config --cflags glib-2.0`
LDFLAGS := -lfuse `pkg-config --libs glib-2.0`
SRCS := imuse.c imapper.c muse_send.c muse_tree.c
OBJS := imuse.o imapper.o muse_send.o muse_tree.o
OUT ?= imuse
README := /dev/null
# "Quiet printing"
ifdef V
ifeq ("$(origin V)", "command line")
Q =
endif
endif
ifndef V
Q = @
endif
QUIET_CC = $(Q:@=@echo ' CC '$@;)
QUIET_LINK = $(Q:@=@echo ' LINK '$@;)
QUIET_AR = $(Q:@=@echo ' AR '$@;)
QUIET_RM = $(Q:@=@echo ' RM '$(OBJS);)
# Debug support
ifdef D
ifeq ("$(origin D)", "command line")
CFLAGS+=-DDEBUG
endif
endif
# Git-r-done! (tm)
all::
@echo 'Building $(OUT)'
all:: $(OBJS)
$(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $(OUT) $(OBJS)
%.o: %.c
$(QUIET_CC)$(CC) $(CFLAGS) -o $@ -c $<
clean:
$(QUIET_RM)$(RM) $(OBJS)
really_clean: clean
$(QUIET_RM)$(RM) $(OUT) $(OUT).tar
sense:
@less $(README)

19
README
View File

@ -1,19 +0,0 @@
_
(_) _ __ ___ _ _ ___ ___
| | | '_ ` _ \ | | | | / __| / _ \
| | | | | | | | | |_| | \__ \ | __/
|_| |_| |_| |_| \__,_| |___/ \___|
imuse is an experimental IMAP file-system for FUSE. The general idea behind the project is to present
what equates to "networked data" as any other kind of "networked data" that we're used to (CIFS,
AFS, AFP, SSHFS, FTP, etc), simply as a set of folders and files.
The overall goal of the imuse project is to allow file-system-like traversal of an IMAP mailbox as if
it were "just another filesystem" with emails being representated as simple files on the filesystem.
imuse uses the University of Washington IMAP library (commonly referred to as "c-client") which drives
applications like (Al)pine.

View File

@ -1,12 +0,0 @@
/*
* imuse -- A FUSE filesystem for exposing IMAP accounts as a locally browsable filesystem, neat!
*
* (c) 2009 - R. Tyler Ballance <tyler@monkeypox.org>
*/
#include <imap/c-client.h>
#include "imapper.h"

View File

@ -1,14 +0,0 @@
/*
* imuse -- A FUSE filesystem for exposing IMAP accounts as a locally browsable filesystem, neat!
*
* (c) 2009 - R. Tyler Ballance <tyler@monkeypox.org>
*/
#ifndef __IMAPPER_H
#define __IMAPPER_H
#endif

90
imuse.c
View File

@ -1,90 +0,0 @@
/*
* imuse -- A FUSE filesystem for exposing IMAP accounts as a locally browsable filesystem, neat!
*
* (c) 2009 - R. Tyler Ballance <tyler@monkeypox.org>
*/
#include <fuse.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <glib.h>
#include "muse_tree.h"
static GHashTable *__special_directories = NULL;
static GHashTable *_accounts = NULL;
static int glist_data_compare(GList *a, GList *b)
{
if (a->data == b->data)
return 0;
return -1;
}
static int imuse_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
stbuf = default_stat(stbuf);
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 1;
} else {
++path;
GList *rc = g_list_find_custom(g_hash_table_get_keys(__special_directories), path, (GCompareFunc)(glist_data_compare));
if (rc) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
return 0;
}
return -ENOENT;
}
return 0;
}
static int imuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fuse_info)
{
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
GList *keys = g_hash_table_get_keys(__special_directories);
GList *key = g_list_first(keys);
do {
filler(buf, key->data, NULL, 0);
} while(key = g_list_next(key));
return 0;
}
static int imuse_open(const char *path, struct fuse_file_info *fuse_info)
{
return 0;
}
static int imuse_read(const char *path, char *buffer, size_t size, off_t offset, struct fuse_file_info *fuse_info)
{
return 0;
}
static struct fuse_operations imuse_operations = { .getattr = imuse_getattr, .readdir = imuse_readdir, .open = imuse_open, .read = imuse_read };
int main(int argc, char *argv[])
{
__special_directories = g_hash_table_new(NULL, g_str_equal);
_accounts = g_hash_table_new(NULL, g_str_equal);
/* Our keys will eventually turn into "special properties" about our make believe directories */
g_hash_table_insert(__special_directories, "Accounts", g_hash_table_new(NULL, NULL));
g_hash_table_insert(__special_directories, "Settings", g_hash_table_new(NULL, NULL));
return fuse_main(argc, argv, &imuse_operations);
}

93
index.html Normal file
View File

@ -0,0 +1,93 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>rtyler/imuse @ GitHub</title>
<style type="text/css">
body {
margin-top: 1.0em;
background-color: #e4e017;
font-family: "helvetica";
color: #000000;
}
#container {
margin: 0 auto;
width: 700px;
}
h1 { font-size: 3.8em; color: #1b1fe8; margin-bottom: 3px; }
h1 .small { font-size: 0.4em; }
h1 a { text-decoration: none }
h2 { font-size: 1.5em; color: #1b1fe8; }
h3 { text-align: center; color: #1b1fe8; }
a { color: #1b1fe8; }
.description { font-size: 1.2em; margin-bottom: 30px; margin-top: 30px; font-style: italic;}
.download { float: right; }
pre { background: #000; color: #fff; padding: 15px;}
hr { border: 0; width: 80%; border-bottom: 1px solid #aaa}
.footer { text-align:center; padding-top:30px; font-style: italic; }
</style>
</head>
<body>
<a href="http://github.com/rtyler/imuse"><img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub" /></a>
<div id="container">
<div class="download">
<a href="http://github.com/rtyler/imuse/zipball/master">
<img border="0" width="90" src="http://github.com/images/modules/download/zip.png"></a>
<a href="http://github.com/rtyler/imuse/tarball/master">
<img border="0" width="90" src="http://github.com/images/modules/download/tar.png"></a>
</div>
<h1><a href="http://github.com/rtyler/imuse">imuse</a>
<span class="small">by <a href="http://github.com/rtyler">rtyler</a></small></h1>
<div class="description">
Experimental (attempted) FUSE filesystem to represent IMAP accounts
</div>
<p>imuse is an experimental IMAP file-system for FUSE. The general idea behind the project is to present
what equates to "networked data" as any other kind of "networked data" that we're used to (CIFS,
AFS, AFP, SSHFS, FTP, etc), simply as a set of folders and files.
The overall goal of the imuse project is to allow file-system-like traversal of an IMAP mailbox as if
it were "just another filesystem" with emails being representated as simple files on the filesystem.
imuse uses the University of Washington IMAP library (commonly referred to as "c-client") which drives
applications like (Al)pine.
</p><h2>Dependencies</h2>
<p>imaplib</p>
<h2>License</h2>
<p>3-clause BSD </p>
<h2>Authors</h2>
<p>R. Tyler Ballance (tyler@monkeypox.org) <br/> <br/> </p>
<h2>Contact</h2>
<p>R. Tyler Ballance (tyler@monkeypox.org) <br/> </p>
<h2>Download</h2>
<p>
You can download this project in either
<a href="http://github.com/rtyler/imuse/zipball/master">zip</a> or
<a href="http://github.com/rtyler/imuse/tarball/master">tar</a> formats.
</p>
<p>You can also clone the project with <a href="http://git-scm.com">Git</a>
by running:
<pre>$ git clone git://github.com/rtyler/imuse</pre>
</p>
<div class="footer">
get the source code on GitHub : <a href="http://github.com/rtyler/imuse">rtyler/imuse</a>
</div>
</div>
</body>
</html>

View File

@ -1,18 +0,0 @@
/*
* imuse -- A FUSE filesystem for exposing IMAP accounts as a locally browsable filesystem, neat!
*
* (c) 2009 - R. Tyler Ballance <tyler@monkeypox.org>
*/
#include <glib.h>
#include <imap/c-client.h>
#include "muse_send.h"
struct muse_send_config *config_by_account(const char *accountname) {
return NULL;
}

View File

@ -1,20 +0,0 @@
/*
* imuse -- A FUSE filesystem for exposing IMAP accounts as a locally browsable filesystem, neat!
*
* (c) 2009 - R. Tyler Ballance <tyler@monkeypox.org>
*/
#ifndef __MUSE_SEND_H
#define __MUSE_SEND_H
struct muse_send_config {
char *hostname;
char *sender_handle;
char *sender_host;
long options;
};
extern struct muse_send_config *config_by_account;
#endif

View File

@ -1,71 +0,0 @@
/*
* imuse -- A FUSE filesystem for exposing IMAP accounts as a locally browsable filesystem, neat!
*
* (c) 2009 - R. Tyler Ballance <tyler@monkeypox.org>
*/
/*
* muse_tree:
* Defines functions for dealing with IMAP's as a GNode-based tree
*
* Abstract:
* The basic idea is to store some basic IMAP meta-data in memory as a large GNode N-ary tree:
* Accounts/
* |--> (d) github.com
* |--> (f) NewEmail.template
* |--> (d) INBOX
* | |--> (d) INBOX.other
* |--> (d) Junk
* |--> (d) Sent
* |--> (f) Some_Email_Subject-(2009-01-16).email
*
* The file "NewEmail.template" will represent a blank email and be a "special" file, whereas the
* directories will be different typed nodes in the tree, files would be another node type.
*
* This way the FUSE integration will simply need to know how to navigate these trees and parse out
* pathes in such a way that it can map back to a particular level in the tree. Operations like open(2)
* or read(2) will need to pass through to their appropriate node-type handlers (email_open(), dir_open(),
* and special_open())
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <glib.h>
#include "muse_tree.h"
int muse_tree_attrs_by_path(const char *path, struct stat *s) {
return -ENOENT;
}
struct stat *default_stat(struct stat *s) {
if (s == NULL)
s = (struct stat *)(malloc(sizeof(struct stat)));
memset(s, 0, sizeof(struct stat));
s->st_mode = 0;
s->st_ino = 0;
s->st_dev = 0;
s->st_nlink = 0;
s->st_uid = getuid();
s->st_gid = getgid();
s->st_size = 0;
s->st_atime = time(NULL);
s->st_mtime = time(NULL);
s->st_ctime = time(NULL);
return s;
}

View File

@ -1,35 +0,0 @@
/*
* imuse -- A FUSE filesystem for exposing IMAP accounts as a locally browsable filesystem, neat!
*
* (c) 2009 - R. Tyler Ballance <tyler@monkeypox.org>
*/
#ifndef __MUSE_TREE_H
#define __MUSE_TREE_H
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#define NODE_TYPE_EMAIL 1334
#define NODE_TYPE_DIR 1335
#define NODE_TYPE_FILE 1336
#define NODE_TYPE_SPECIAL 1337
struct muse_tree_node {
unsigned int type;
char *display_name;
struct stat *st;
void *node_data;
};
struct muse_tree_email_node;
struct muse_tree_dir_node;
struct must_tree_file_node;
struct muse_tree_special_node;
extern struct stat *default_stat(struct stat *);
extern int muse_tree_attrs_by_path(const char *, struct stat *);
#endif

View File

@ -1,36 +0,0 @@
# Standard definitions
CC ?= gcc
TAR ?= tar
RM ?= -rm
CFLAGS := -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=22 -g `pkg-config --cflags glib-2.0`
LDFLAGS := -lfuse -lcunit -lncurses `pkg-config --libs glib-2.0` -lssl -lpam -lc-client
# "Quiet printing"
ifdef V
ifeq ("$(origin V)", "command line")
Q =
endif
endif
ifndef V
Q = @
endif
QUIET_CC = $(Q:@=@echo ' CC '$@;)
QUIET_LINK = $(Q:@=@echo ' LINK '$@;)
QUIET_AR = $(Q:@=@echo ' AR '$@;)
QUIET_RM = $(Q:@=@echo ' RM '$(OBJS);)
# Debug support
ifdef D
ifeq ("$(origin D)", "command line")
CFLAGS+=-DDEBUG
endif
endif
%.o: %.c
$(QUIET_CC)$(CC) $(CFLAGS) -o $@ -c $<
clean:
$(QUIET_RM)$(RM) $(OBJS)
really_clean: clean
$(QUIET_RM)$(RM) $(OUT) $(OUT).tar

View File

@ -1,79 +0,0 @@
/*
* Testing for the config file handling code
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <glib.h>
#include <glib/gprintf.h>
#include <CUnit/Basic.h>
void test_Void() {
CU_ASSERT(true == true);
}
void test_BasicConfigSample() {
GKeyFile *file = g_key_file_new();
CU_ASSERT_PTR_NOT_NULL(file);
CU_ASSERT(TRUE == g_key_file_load_from_file(file, "config.sample.ini", G_KEY_FILE_NONE, NULL));
char **groups = g_key_file_get_groups(file, NULL);
CU_ASSERT_PTR_NOT_NULL(groups);
int i = 0;
char *group = groups[i];
while (group != NULL) {
group = groups[++i];
}
CU_ASSERT(i == 2);
CU_ASSERT_STRING_EQUAL(groups[0], "General");
CU_ASSERT_STRING_EQUAL(groups[1], "Account");
g_strfreev(groups);
CU_ASSERT(g_key_file_get_integer(file, "General", "PollInterval", NULL) == 5);
CU_ASSERT_STRING_EQUAL(g_key_file_get_string(file, "Account", "ReadServer", NULL), "imap.dot.com");
CU_ASSERT_STRING_EQUAL(g_key_file_get_string(file, "Account", "WriteServer", NULL), "smtp.dot.com");
CU_ASSERT_STRING_EQUAL(g_key_file_get_string(file, "Account", "Username", NULL), "someguy");
g_key_file_free(file);
}
int main() {
CU_pSuite pSuite = NULL;
/* initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
/* add a suite to the registry */
pSuite = CU_add_suite("Config_Suite", NULL, NULL);
if (NULL == pSuite) {
CU_cleanup_registry();
return CU_get_error();
}
/* add the tests to the suite */
/* NOTE - ORDER IS IMPORTANT - MUST TEST fread() AFTER fprintf() */
if (
(NULL == CU_add_test(pSuite, "empty test", test_Void)) ||
(NULL == CU_add_test(pSuite, "test reading config.sample", test_BasicConfigSample))
)
{
CU_cleanup_registry();
return CU_get_error();
}
/* Run all tests using the CUnit Basic interface */
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
CU_cleanup_registry();
return CU_get_error();
}

View File

@ -1,13 +0,0 @@
#
# config.sample: This is a sample configuration file for imuse, to be used for testing purposes only
#
[General]
# How often should imuse poll IMAP (in minutes)
PollInterval=5
[Account]
ReadServer=imap.dot.com
WriteServer=smtp.dot.com
Username=someguy

View File

@ -1,139 +0,0 @@
/*
* Testing for the smtp sending code
*/
#include <stdio.h>
#include <glib.h>
#include <imap/c-client.h>
#include <CUnit/Basic.h>
#define SMTP_HOST "smtp.dot.com"
#define SMTP_RECIP "imuse@dot.com"
void mm_flags(MAILSTREAM *stream, unsigned long number) { printf("Calling mm_flags\n"); return; }
void mm_status(MAILSTREAM *stream, char *mailbox, MAILSTATUS *status) { printf("Calling mm_status\n"); return; }
void mm_searched(MAILSTREAM *stream, unsigned long number) { printf("Calling mm_searched\n"); return; }
void mm_exists(MAILSTREAM *stream, unsigned long number) { printf("Calling mm_exists\n"); return; }
void mm_expunged(MAILSTREAM *stream, unsigned long number) { printf("Calling mm_expunged\n"); return; }
void mm_list(MAILSTREAM *stream, int delim, char *name, long attrib) { printf("Calling mm_list\n"); return; }
void mm_log(char *string,long errflg) {
printf("==(mm_log)==> %s\n", string);
return;
}
void mm_lsub(MAILSTREAM *stream,int delimiter,char *name,long attributes) { printf("Calling mm_lsub\n"); return; }
void mm_fatal(char *string) { printf("Calling mm_fatal\n"); return; }
long mm_diskerror(MAILSTREAM *stream,long errcode,long serious) { printf("Calling mm_diskerror\n"); return 0L; }
void mm_dlog(char *string) {
printf("==(mm_dlog)==> %s\n", string);
return;
}
void mm_notify(MAILSTREAM *stream,char *string,long errflg) { printf("Calling mm_notify\n"); return; }
void mm_critical(MAILSTREAM *stream) { printf("Calling mm_critical\n"); return; }
void mm_nocritical(MAILSTREAM *stream) { printf("Calling mm_nocritical\n"); return;}
void mm_login(NETMBX *mb,char *user,char *pwd,long trial) { printf("Calling mm_login\n"); return; }
void test_Void() {
CU_ASSERT(TRUE == TRUE);
}
void test_BasicSendMail() {
char *server = SMTP_HOST;
char *recip = SMTP_RECIP;
long smtp_options = 0L;
if (getenv("SMTP_HOST") && getenv("SMTP_RECIP")) {
server = getenv("SMTP_HOST");
recip = getenv("SMTP_RECIP");
}
CU_ASSERT_STRING_NOT_EQUAL_FATAL(server, SMTP_HOST);
CU_ASSERT_STRING_NOT_EQUAL_FATAL(recip, SMTP_RECIP);
char *servers[] = {server};
SENDSTREAM *stream = smtp_open(servers, smtp_options);
CU_ASSERT_PTR_NOT_NULL(stream);
char *name = "Unit Tester";
char *sender_email = "imuse-unit-test";
char *sender_host = mylocalhost();
char *bodytext = (char *)(fs_get(8*MAILTMPLEN));
ENVELOPE *envelope = mail_newenvelope();
BODY *body = mail_newbody();
envelope->from = mail_newaddr();
envelope->from->personal = cpystr(name);
envelope->from->mailbox = cpystr(sender_email);
envelope->from->host = cpystr(sender_host);
envelope->return_path = mail_newaddr();
envelope->return_path->mailbox = cpystr(sender_email);
envelope->return_path->host = cpystr(sender_host);
rfc822_parse_adrlist(&envelope->to, cpystr(recip), sender_host);
envelope->subject = cpystr("test_BasicSendMail");
body->type = TYPETEXT;
snprintf(bodytext, (8*MAILTMPLEN), "This is a simple text body");
body->contents.text.data = (unsigned char *)(bodytext);
body->contents.text.size = strlen(bodytext);
envelope->date = (char *)(fs_get(1 + MAILTMPLEN));
rfc822_date(envelope->date);
if (stream) {
printf("Sending...\n");
if (smtp_mail(stream, "MAIL", envelope, body)) {
printf("Okay, %s\n", stream->reply);
}
else {
printf("Fail, %s\n", stream->reply);
}
}
// Make sure we successfully sent
CU_ASSERT_EQUAL(stream->replycode, 250);
mail_free_envelope(&envelope);
mail_free_body(&body);
if (stream) {
smtp_close(stream);
}
}
int main() {
CU_pSuite pSuite = NULL;
/* initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
/* add a suite to the registry */
pSuite = CU_add_suite("Smtp_Suite", NULL, NULL);
if (NULL == pSuite) {
CU_cleanup_registry();
return CU_get_error();
}
/* add the tests to the suite */
/* NOTE - ORDER IS IMPORTANT - MUST TEST fread() AFTER fprintf() */
if (
(NULL == CU_add_test(pSuite, "empty test", test_Void)) ||
(NULL == CU_add_test(pSuite, "sending a basic email", test_BasicSendMail))
)
{
CU_cleanup_registry();
return CU_get_error();
}
/* Run all tests using the CUnit Basic interface */
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
CU_cleanup_registry();
return CU_get_error();
}