static char rcsid[] = "@(#)$Id: shared_mbox.c,v 1.7 2006/06/29 17:26:41 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.7 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* or Kari Hurtta <elm@elmme-mailer.org>
*****************************************************************************/
/*
* This file is compiled only if dlopen() is available, so
* that file does not need to be guarded with #ifdef
*/
#include "def_mbox.h"
DEBUG_VAR(Debug,__FILE__,"dl");
#include "shared_imp.h"
#include "rc_imp.h"
#include "save_opts.h"
#include "cs_imp.h"
#include "ss_imp.h"
#if ANSI_C
#define S_(x) static x;
#else
#define S_(x)
#endif
static struct shared_POP_CAPA {
char * capa;
int priority;
struct ImpInfo * imp_idx;
pop_capa_handler *capa_handler;
} * shared_pop_capas = NULL;
static int shared_pop_capa_count = 0;
static struct shared_IMAP_CAPA {
char * capa;
int priority;
struct ImpInfo * imp_idx;
imap_capa_handler *capa_handler;
} * shared_imap_capas = NULL;
static int shared_imap_capa_count = 0;
#define SHARED_MBOX_magic 0xF905
struct sl_mbox_data {
uint16 magic;
};
S_(sl_reg_functions sl_reg_mbox)
static int sl_reg_mbox P_((struct ImpInfo *i,
int reg_idx));
static int sl_reg_mbox(i,reg_idx)
struct ImpInfo *i;
int reg_idx;
{
/* union hack to avoid warnings about casting
* between pointer-to-object and pointer-to-function
*/
int res = 0;
union F2 {
void * ptr;
provides_shared_FT_f * f2;
} f2; /* not in use */
union F4 {
void * ptr;
provides_shared_POP_CAPA_f * f4;
} f4;
union F5 {
void * ptr;
provides_shared_IMAP_CAPA_f * f5;
} f5;
/* not in use */
f2.ptr = dlsym(i->handle, "provides_shared_FT");
f4.ptr = dlsym(i->handle, "provides_shared_POP_CAPA");
f5.ptr = dlsym(i->handle, "provides_shared_IMAP_CAPA");
if (!f2.f2) {
DPRINT(Debug,7,(&Debug, " ... NO provides_shared_FT\n"));
}
if (!f4.f4) {
DPRINT(Debug,7,(&Debug, " ... NO provides_shared_POP_CAPA\n"));
}
if (!f5.f5) {
DPRINT(Debug,7,(&Debug, " ... NO provides_shared_IMAP_CAPA\n"));
}
if (f2.f2) {
int count,x;
size_t s_res2;
struct folder_type ** res2 = f2.f2(&count, &s_res2);
if (s_res2 != sizeof (**res2)) {
DPRINT(Debug,1,(&Debug,"... (folder_type_p) mismatch: %d should be %d\n",
s_res2, sizeof (**res2)));
} else {
shared_folder_types =
safe_realloc(shared_folder_types,
sizeof (shared_folder_types[0]) *
(shared_folder_type_count + count));
res = 1;
DPRINT(Debug,7,(&Debug," ... provides_shared_FT: (shared_folder_types) count %d\n",
count));
for (x = 0; x < count; x++) {
shared_folder_types[shared_folder_type_count
+x].T = res2[x];
#if 0
shared_folder_types[shared_folder_type_count
+x].portnum = res2[x].portnum;
#endif
shared_folder_types[shared_folder_type_count
+x].imp_idx = i;
}
shared_folder_type_count += count;
}
}
#ifdef REMOTE_MBX
if (f4.f4) {
int count,x;
size_t s_res4;
struct provides_shared_POP_CAPA * res4 = f4.f4(&count, &s_res4);
if (s_res4 != sizeof (*res4)) {
DPRINT(Debug,1,(&Debug,
"... struct provides_shared_POP_CAPA mismatch: %d should be %d\n",
s_res4,sizeof (*res4)));
} else {
shared_pop_capas =
safe_realloc(shared_pop_capas,
sizeof (shared_pop_capas[0]) *
(shared_pop_capa_count + count));
DPRINT(Debug,7,(&Debug," ... provides_shared_IMAP_CAPA: (shared_pop_capas) count %d\n",
count));
res = 1;
for (x = 0; x < count; x++) {
shared_pop_capas[shared_pop_capa_count
+x].capa = res4[x].capa;
shared_pop_capas[shared_pop_capa_count
+x].priority = res4[x].priority;
shared_pop_capas[shared_pop_capa_count
+x].capa_handler = res4[x].capa_handler;
shared_pop_capas[shared_pop_capa_count
+x].imp_idx = i;
DPRINT(Debug,8,(&Debug,
"library %s provides POP %s\n",
i->shname,
res4[x].capa));
}
shared_pop_capa_count += count;
}
}
#endif
if (f5.f5) {
int count,x;
size_t s_res5;
struct provides_shared_IMAP_CAPA * res5 = f5.f5(&count, &s_res5);
if (s_res5 != sizeof (*res5)) {
DPRINT(Debug,1,(&Debug,
"... struct provides_shared_IMAP_CAPA mismatch: %d should be %d\n",
s_res5,sizeof (*res5)));
} else {
shared_imap_capas =
safe_realloc(shared_imap_capas,
sizeof (shared_imap_capas[0]) *
(shared_imap_capa_count + count));
DPRINT(Debug,7,(&Debug," ... provides_shared_IMAP_CAPA: (shared_imap_capas) count %d\n",
count));
res = 1;
for (x = 0; x < count; x++) {
shared_imap_capas[shared_imap_capa_count
+x].capa = res5[x].capa;
shared_imap_capas[shared_imap_capa_count
+x].priority = res5[x].priority;
shared_imap_capas[shared_imap_capa_count
+x].capa_handler =
res5[x].capa_handler;
shared_imap_capas[shared_imap_capa_count
+x].imp_idx = i;
DPRINT(Debug,8,(&Debug,
"library %s provides IMAP %s\n",
i->shname,
res5[x].capa));
}
shared_imap_capa_count += count;
}
}
i->regs[reg_idx].valid = res;
DPRINT(Debug,7,(&Debug,
"sl_reg_mbox: [%p]->regs[%d].valid = %d\n",
i,reg_idx,res));
return res;
}
S_(sl_zero_reg_list sl_zero_mbox)
static void sl_zero_mbox P_((struct dt_shared_info *var,
struct reg_list *r));
static void sl_zero_mbox(var,r)
struct dt_shared_info *var;
struct reg_list *r;
{
r->var = var;
r->valid = 0;
r->r.mbox = safe_malloc(sizeof (*r->r.mbox)); /* never freed ... */
r->r.mbox->magic = SHARED_MBOX_magic;
}
S_(sl_unreg_functions sl_unreg_mbox)
static void sl_unreg_mbox P_((struct ImpInfo *i, int reg_idx));
static void sl_unreg_mbox(i,reg_idx)
struct ImpInfo *i;
int reg_idx;
{
struct reg_list *r = & (i->regs[reg_idx] );
r->valid = 0;
}
static struct shared_loader mbox_loader = {
SHARED_LOADER_magic,
sl_reg_mbox,
sl_zero_mbox,
sl_unreg_mbox
};
SHAREDLIB use_shared_mbox = {
&mbox_loader /* loader */,
0,
NULL, 0,
NULL
};
#ifdef REMOTE_MBX
static enum CAPA_phase pri_to_phase P_((int pri));
static enum CAPA_phase pri_to_phase(pri)
int pri;
{
if (pri < 10)
return capa_prelogin;
if (pri < 20)
return capa_do_login;
return capa_logged;
}
struct POP_capa_libs {
char * capa;
char * capa_args;
struct ImpInfo * imp_idx;
int priority;
pop_capa_handler * capa_handler;
};
void probe_pop_capa_lib(pop_capa_libs,pop_capa_libcount,capa,capa_args)
struct POP_capa_libs * *pop_capa_libs;
int * pop_capa_libcount;
CONST char *capa;
CONST char *capa_args;
{
int i;
load_shared_libs1(&use_shared_mbox);
for (i = 0; i < shared_pop_capa_count; i++) {
/* rfc2449: CAPA response tags are case-insensitive. */
/* Also check that librrary is currently loaded ... */
if (!verify_shared_index(shared_pop_capas[i].imp_idx)) {
DPRINT(Debug,8,(&Debug,"shared_pop_capas[%d] unloaded?\n",i));
continue;
}
if ( 0 == istrcmp(shared_pop_capas[i].capa, capa))
break;
}
if (i >= shared_pop_capa_count)
return; /* Not found */
DPRINT(Debug,8,(&Debug,"shared_pop_capas[%d] is %s\n",i,capa));
*pop_capa_libs = safe_realloc(*pop_capa_libs,
(*pop_capa_libcount +1) *
sizeof ((*pop_capa_libs)[0]));
(*pop_capa_libs)[*pop_capa_libcount].capa = safe_strdup(capa);
(*pop_capa_libs)[*pop_capa_libcount].capa_args =
capa_args ? safe_strdup(capa_args) : NULL;
(*pop_capa_libs)[*pop_capa_libcount].imp_idx =
shared_pop_capas[i].imp_idx;
(*pop_capa_libs)[*pop_capa_libcount].priority =
shared_pop_capas[i].priority;
(*pop_capa_libs)[*pop_capa_libcount].capa_handler =
shared_pop_capas[i].capa_handler;
DPRINT(Debug,7,(&Debug,
"** Using %s library for POP capacity %s\n",
shared_pop_capas[*pop_capa_libcount].
imp_idx->tag,
(*pop_capa_libs)[*pop_capa_libcount].capa));
(*pop_capa_libcount)++;
}
static int pop_capa_compare P_((const void *A, const void *B));
static int pop_capa_compare(A,B)
CONST void *A;
CONST void *B;
{
CONST struct POP_capa_libs *A1 = A;
CONST struct POP_capa_libs *B1 = B;
if (A1->priority < B1->priority)
return -1;
if (A1->priority > B1->priority)
return 1;
return 0;
}
int handle_pop_capa_libs(folder,pop_capa_libs,pop_capa_libcount,phase,commands)
struct folder_info *folder;
struct POP_capa_libs * *pop_capa_libs;
int * pop_capa_libcount;
enum CAPA_phase * phase;
struct pop_callbacks *commands;
{
int ret = 1;
struct remote_account * A;
enum CAPA_phase old_phase = *phase;
if (!folder->p ||
folder->folder_type != &pop_mbx)
panic("CONNECTION PANIC",__FILE__,__LINE__,"handle_pop_capa_libs",
"Not a POP connection",0);
A = &(folder->p->a.pop_mbx.C);
if (*pop_capa_libs) {
int i;
qsort(*pop_capa_libs,*pop_capa_libcount,
sizeof ((*pop_capa_libs)[0]),
pop_capa_compare);
for (i = 0; i < *pop_capa_libcount; i++) {
struct SE_option *config = NULL;
struct SE_option_type *T = NULL;
int j;
if (*phase != pri_to_phase((*pop_capa_libs)[i].priority))
continue;
DPRINT(Debug,8,(&Debug,
"[%d] handling %s with %s library\n",
i,(*pop_capa_libs)[i].capa,
shared_pop_capas[i].imp_idx->tag));
for (j = 0; j < shared_SE_option_type_count; j++) {
if (shared_SE_option_types[j].imp_idx ==
shared_pop_capas[j].imp_idx) {
T = shared_SE_option_types[j].T;
DPRINT(Debug,8,(&Debug,
" ... have service option type %p\n",
T));
}
}
if (A->service_idx >= 0 && T) {
if (A->service_idx >= service_count)
panic("CONNECTION PANIC",__FILE__,__LINE__,
"handle_pop_capa_libs",
"Bad service index",0);
for (j = 0;
j < service_list[A->service_idx].option_count;
j++) {
if (service_list[A->service_idx].
option_list[j].type == T) {
config = & (service_list[A->service_idx].
option_list[j]);
DPRINT(Debug,8,(&Debug,
" ... have service config %p (%s)\n",
config,
config->prefix ? config->prefix : "NONE"));
}
}
}
if (!(*pop_capa_libs)[i].
capa_handler(folder,
(*pop_capa_libs)[i].capa,
(*pop_capa_libs)[i].capa_args,
sizeof (*folder),
commands,
sizeof (*commands),
config,
sizeof (*config),
phase)) {
ret = 0;
goto fail;
}
if (*phase != old_phase) {
DPRINT(Debug,8,(&Debug," ... done (phase changed)\n"));
break;
}
}
fail:
free(*pop_capa_libs);
*pop_capa_libs = NULL;
*pop_capa_libcount = 0;
}
return ret;
}
struct IMAP_capa_libs {
char * capa;
struct ImpInfo * imp_idx;
int priority;
imap_capa_handler * capa_handler;
};
void probe_imap_capa_lib(imap_capa_libs,imap_capa_libcount,capa)
struct IMAP_capa_libs * *imap_capa_libs;
int * imap_capa_libcount;
CONST char *capa;
{
int i;
load_shared_libs1(&use_shared_mbox);
for (i = 0; i < shared_imap_capa_count; i++) {
/* rfc2460: (Syntax) Except as noted otherwise,
all alphabetic characters are case-insensitive.
*/
/* Also check that library is currently loaded ... */
if (!verify_shared_index(shared_imap_capas[i].imp_idx)) {
DPRINT(Debug,8,(&Debug,"shared_imap_capas[%d] unloaded?\n",i));
continue;
}
if ( 0 == istrcmp(shared_imap_capas[i].capa, capa))
break;
}
if (i >= shared_imap_capa_count)
return; /* Not found */
DPRINT(Debug,8,(&Debug,"shared_imap_capas[%d] unloaded is %s\n",i,capa));
*imap_capa_libs = safe_realloc(*imap_capa_libs,
(*imap_capa_libcount +1) *
sizeof ((*imap_capa_libs)[0]));
(*imap_capa_libs)[*imap_capa_libcount].capa = safe_strdup(capa);
(*imap_capa_libs)[*imap_capa_libcount].imp_idx =
shared_imap_capas[i].imp_idx;
(*imap_capa_libs)[*imap_capa_libcount].priority =
shared_imap_capas[i].priority;
(*imap_capa_libs)[*imap_capa_libcount].capa_handler =
shared_imap_capas[i].capa_handler;
DPRINT(Debug,7,(&Debug,
"** Using %s library for IMAP capacity %s\n",
shared_imap_capas[*imap_capa_libcount].imp_idx->tag,
(*imap_capa_libs)[*imap_capa_libcount].capa));
(*imap_capa_libcount)++;
}
static int imap_capa_compare P_((const void *A, const void *B));
static int imap_capa_compare(A,B)
CONST void *A;
CONST void *B;
{
CONST struct IMAP_capa_libs *A1 = A;
CONST struct IMAP_capa_libs *B1 = B;
if (A1->priority < B1->priority)
return -1;
if (A1->priority > B1->priority)
return 1;
return 0;
}
int handle_imap_capa_libs(con,imap_capa_libs,imap_capa_libcount,phase,commands)
struct connection_cache *con;
struct IMAP_capa_libs * *imap_capa_libs;
int * imap_capa_libcount;
enum CAPA_phase * phase;
struct imap_callbacks *commands;
{
int ret = 1;
struct remote_account * A;
enum CAPA_phase old_phase = *phase;
if (con->type != &IMAP_connection)
panic("CONNECTION PANIC",__FILE__,__LINE__,"handle_imap_capa_libs",
"Not a imap connection",0);
A = &(con->C);
if (*imap_capa_libs) {
int i;
qsort(*imap_capa_libs,*imap_capa_libcount,
sizeof ((*imap_capa_libs)[0]),
imap_capa_compare);
for (i = 0; i < *imap_capa_libcount; i++) {
struct SE_option *config = NULL;
struct SE_option_type *T = NULL;
int j;
if (*phase != pri_to_phase((*imap_capa_libs)[i].priority))
continue;
DPRINT(Debug,8,(&Debug,
"[%d] handling %s with %s library\n",
i,(*imap_capa_libs)[i].capa,
shared_imap_capas[i].imp_idx->tag));
for (j = 0; j < shared_SE_option_type_count; j++) {
if (shared_SE_option_types[j].imp_idx ==
shared_pop_capas[j].imp_idx) {
T = shared_SE_option_types[j].T;
DPRINT(Debug,8,(&Debug,
" ... have service option type %p\n",
T));
}
}
if (A->service_idx >= 0 && T) {
if (A->service_idx >= service_count)
panic("CONNECTION PANIC",__FILE__,__LINE__,
"handle_pop_capa_libs",
"Bad service index",0);
for (j = 0;
j < service_list[A->service_idx].option_count;
j++) {
if (service_list[A->service_idx].
option_list[j].type == T) {
config = & (service_list[A->service_idx].
option_list[j]);
DPRINT(Debug,8,(&Debug,
" ... have service config %p (%s)\n",
config,
config->prefix ? config->prefix :
"NONE"));
}
}
}
if (!(*imap_capa_libs)[i].
capa_handler(con,
(*imap_capa_libs)[i].capa,
sizeof (*con),
commands,
sizeof (*commands),
config,
sizeof (*config),
phase)) {
ret = 0;
goto fail;
}
if (old_phase != *phase) {
DPRINT(Debug,8,(&Debug," ... done (phase changed)\n"));
break;
}
}
fail:
;
}
free_only_imap_capa_libs(imap_capa_libs,imap_capa_libcount);
return ret;
}
void free_only_imap_capa_libs(imap_capa_libs,imap_capa_libcount)
struct IMAP_capa_libs * *imap_capa_libs;
int * imap_capa_libcount;
{
if (*imap_capa_libs) {
int i;
for (i = 0; i < *imap_capa_libcount; i++) {
if ((*imap_capa_libs)[i].capa) {
free((*imap_capa_libs)[i].capa);
(*imap_capa_libs)[i].capa = NULL;
}
}
free(*imap_capa_libs);
*imap_capa_libs = NULL;
*imap_capa_libcount = 0;
}
}
#endif
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1