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 * or Kari Hurtta *****************************************************************************/ /* * 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: */