static char rcsid[] = "@(#)$Id: savefolder.c,v 1.11 2006/08/09 16:12:28 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.11 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
* or Kari Hurtta <elm@elmme-mailer.org>
*****************************************************************************
* Some local mailbox code based on ../src/file.c.
* That code was following copyright:
*
* The Elm Mail System
*
* Copyright (c) 1988-1992 USENET Community Trust
* Copyright (c) 1986,1987 Dave Taylor
*
*
*****************************************************************************/
#include "def_mbox.h"
#include "s_me.h"
DEBUG_VAR(Debug,__FILE__,"mbox");
#if ANSI_C
#define S_(x) static x;
#else
#define S_(x)
#endif
static unsigned char * s2us P_((char *str));
static unsigned char * s2us(str)
char *str;
{
return (unsigned char *)str;
}
static char *us2s P_((unsigned char *str));
static char *us2s(str)
unsigned char *str;
{
return (char *)str;
}
/* ---------------------------------------------------------------------- */
static int change_type P_((struct folder_browser *dir,
struct browser_type *new_type));
/* Dummy browser */
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
static void browser_zero_dummy P_((struct folder_browser *dir));
static void browser_zero_dummy(dir)
struct folder_browser *dir;
{
DPRINT(Debug,11,(&Debug,"browser_zero_local: dir=%p\n", dir));
dir->a.dummy_browser.remote = NULL;
}
static void browser_free_dummy P_((struct folder_browser *dir));
static void browser_free_dummy(dir)
struct folder_browser *dir;
{
DPRINT(Debug,11,(&Debug,"browser_free_local: dir=%p\n", dir));
if (dir->a.dummy_browser.remote) {
free(dir->a.dummy_browser.remote);
dir->a.dummy_browser.remote = NULL;
}
}
#ifdef REMOTE_MBX
static int dummy_to_imap P_((struct folder_browser *dir));
static int dummy_to_imap(dir)
struct folder_browser *dir;
{
int ret = 0;
struct remote_account X;
struct service_entry *se = NULL;
char *rest = NULL;
int code;
zero_remote_account(&X);
DPRINT(Debug,15,(&Debug,
"dummy_to_imap: Trying %s as remote address...\n",
dir->a.dummy_browser.remote));
/* -1 == name not found or bad syntax
0 == not a remote address
1 == name found
*/
if (0 <= (code = split_remote_name(dir->a.dummy_browser.remote,
&X,&se,&rest,
STFLAG_is_imap /* Need IMAP */
))) {
struct connection_cache *CX;
PORTS ports_imaponly[] = { PORT_imap4, PORT_end };
int got;
if (code == 0 || rest)
panic("BROWSER PANIC",__FILE__,__LINE__,"dummy_to_imap",
"Bad return from split_remote_name",0);
DPRINT(Debug,15,(&Debug,
"dummy_to_imap: Using user=%s host=%s\n",
X.username,X.host));
/* Only IMAP connections are cached */
CX = locate_from_cache(X.username,X.host,&IMAP_connection,
0 /* Default port */);
if (CX) {
DPRINT(Debug,10,(&Debug,
"dummy_to_imap: Changing browser to IMAP browser\n"));
change_type(dir,&imap_browser);
clear_dir_vector(dir);
browser_from_connection(CX,dir);
ret = 1;
} else if (connect_remote_account(&X,&got,se,ports_imaponly,
PORT_end)) {
DPRINT(Debug,10,(&Debug,
"dummy_to_imap: Changing browser to IMAP browser\n"));
change_type(dir,&imap_browser);
clear_dir_vector(dir);
ret = join_connection(dir->a.imap_browser.Ch,&X,
CON_greeting);
}
}
free_remote_account(&X);
free_temporary_service_entry(&se);
DPRINT(Debug,15,(&Debug,"dummy_to_imap=%d\n",ret));
return ret;
}
#endif /* REMOTE_MBX */
/* Returns name relative to directory of browser */
static struct string * browser_descend_dummy P_((struct folder_browser *dir,
const struct string *rel_name));
static struct string * browser_descend_dummy(dir,rel_name)
struct folder_browser *dir;
CONST struct string *rel_name;
{
int L, idx;
static struct string * ret = NULL;
int last_idx_ok = -1;
DPRINT(Debug,12,(&Debug,"browser_descend_dummy: dir=%p, ", dir));
if (!rel_name) {
DPRINT(Debug,12,(&Debug,"rel_name=NULL\n"));
DPRINT(Debug,12,(&Debug,"browser_descend_dummy=NULL\n"));
return NULL;
}
DPRINT(Debug,12,(&Debug,"rel_name=%S\n",rel_name));
L = string_len(rel_name);
for (idx = 0; idx < L ; idx++) {
uint16 code = give_unicode_from_string(rel_name,idx);
if (0x002F /* '/' */ == code) {
int X1 = 0;
/* 1) First check is current path have same prefix ... */
struct string * A1 = clip_from_string(rel_name,&X1,idx+1);
if (dir->dirname) {
int X2 = 0;
struct string * A2 = clip_from_string(dir->dirname,&X2,idx+1);
if (X1 == X2 &&
0 == string_cmp(A1,A2,-99 /* Unknown indicator */ )) {
DPRINT(Debug,12,(&Debug,
"browser_descend_dummy: sep idx=%d -- so far ok\n",
idx));
last_idx_ok = idx;
free_string(&A1);
free_string(&A2);
continue;
}
free_string(&A2);
}
/* 2) Then check if current path have prefix of wanted */
if (!dir->dirname ||
0 != string_cmp(A1,dir->dirname,
-99 /* unknown indicator */)) {
struct string * Lstr =
convert_string(local_fs_charset,A1,0);
unsigned char * str =
stream_from_string(Lstr,0,NULL);
struct stat buf;
DPRINT(Debug,12,(&Debug,
"browser_descend_dummy: sep idx=%d -- need change of directory\n",
idx));
if (0 != stat(us2s(str),&buf)
#ifdef S_ISDIR
|| !S_ISDIR(buf.st_mode)
#endif
) {
DPRINT(Debug,12,(&Debug,
"browser_descend_dummy: Failed -- bailing out\n"));
free_string(&A1);
free_string(&Lstr);
free(str);
break;
}
/* Make empty selection folder */
clear_dir_vector(dir);
if (dir->dirname)
free_string(&dir->dirname);
dir->dirname = Lstr;
Lstr = NULL;
if (dir->sys_dir) {
free(dir->sys_dir);
dir->sys_dir = NULL;
}
dir->sys_dir = us2s(str);
str = NULL;
}
DPRINT(Debug,12,(&Debug,
"browser_descend_dummy: sep idx=%d -- ok\n",
idx));
last_idx_ok = idx;
free_string(&A1);
}
}
DPRINT(Debug,12,(&Debug,
"browser_descend_dummy: Up to %d OK\n",last_idx_ok));
last_idx_ok++;
ret = clip_from_string(rel_name,&last_idx_ok,string_len(rel_name));
DPRINT(Debug,10,(&Debug,
"*** %S as relative to %S is %S\n",
rel_name,dir->dirname,ret));
DPRINT(Debug,12,(&Debug,
"browser_descend_dummy=%S -- consumed to %d\n",
ret,last_idx_ok));
return ret;
}
/* rel_dirname is relative to type -- not include user@hostname
rel_dirname is NULL is indicating that selection is on
dir->a.dummy_browser.remote
*/
/* This assumes that NO default directory --
* because there is no directory listing
* that is NO-OP
*/
static int browser_change_v_dummy P_((struct folder_browser *dir,
struct name_vector *X,
struct string **dispname));
static int browser_change_v_dummy(dir,X,dispname)
struct folder_browser *dir;
struct name_vector *X;
struct string **dispname;
{
DPRINT(Debug,11,(&Debug,"browser_change_v_dummy=0: dir=%p\n", dir));
return 0; /* UNSUPPORTED */
}
static void browser_gen_default_menu P_((struct folder_browser *dir));
static void browser_gen_default_menu(dir)
struct folder_browser *dir;
{
DPRINT(Debug,11,(&Debug,"browser_gen_default_menu: dir=%p\n", dir));
/* Make top level selection folder */
clear_dir_vector(dir);
if (dir->dirname)
free_string(&dir->dirname);
if (dir->sys_dir) {
free(dir->sys_dir);
dir->sys_dir = NULL;
}
/* Local default directory (also the last folder used on src/file.c) */
if (0 == access(".",READ_ACCESS)) {
/* WARNING: add_dir_vector does not allocate strings --
* it just assign pointers!
*/
add_dir_vector(dir,
safe_strdup("."),new_string2(local_fs_charset,
s2us(".")),
BROWSER_NOFOLDER);
}
switch(dir->sel_type) {
case selection_folder:
{
/* give_dt_estr_as_str adds / to end */
char * folders_val = give_dt_estr_as_str(&folders_e,"maildir");
/* Local folders directory */
if (folders_val && 0 == access(folders_val,READ_ACCESS)) {
char * str = safe_strdup(folders_val);
/* WARNING: add_dir_vector does not allocate strings --
* it just assign pointers!
*/
add_dir_vector(dir,str,new_string2(system_charset,s2us("=")),
BROWSER_NOFOLDER);
}
}
{
char * default_val = give_dt_estr_as_str(&defaultfile_e,"incoming-mailbox");
/* Incoming mailbox (may also be IMAP mailbox) */
if (default_val) {
/* WARNING: add_dir_vector does not allocate strings --
* it just assign pointers!
*/
add_dir_vector(dir,
safe_strdup(default_val),
new_string2(system_charset,s2us("!")),
BROWSER_NODIR);
}
}
{
char * recvd_val = give_dt_estr_as_str(&recvd_mail_e,"receivedmail");
/* ">" -- usually =received folder */
if (recvd_val) {
/* WARNING: add_dir_vector does not allocate strings --
* it just assign pointers!
*/
add_dir_vector(dir,
safe_strdup(recvd_val),
new_string2(system_charset,s2us(">")),
BROWSER_NODIR);
}
}
{
char * sent_val = give_dt_estr_as_str(&sent_mail_e,"sentmail");
/* "<" -- usually =sent folder */
if (sent_val) {
/* WARNING: add_dir_vector does not allocate strings --
* it just assign pointers!
*/
add_dir_vector(dir,
safe_strdup(sent_val),
new_string2(system_charset,s2us("<")),
BROWSER_NODIR);
}
}
break;
case selection_file:
/* Local root */
if (0 == access("/",READ_ACCESS)) {
/* WARNING: add_dir_vector does not allocate strings --
* it just assign pointers!
*/
add_dir_vector(dir,
safe_strdup("/"),
new_string2(system_charset,s2us("/")),
BROWSER_NOFOLDER);
}
{
char * attachment_dir_val =
give_dt_estr_as_str(&attachment_dir_e,
"attachment-dir");
/* Attachment directory for {doc}/ */
if (attachment_dir_val &&
0 == access(attachment_dir_val,READ_ACCESS)) {
/* WARNING: add_dir_vector does not allocate strings --
* it just assign pointers!
*/
add_dir_vector(dir,
elm_message(FRM("%s/"),attachment_dir_val),
new_string2(system_charset,s2us("{doc}/")),
BROWSER_NOFOLDER);
}
}
break;
}
/* User's local home directory */
if (home[0] && 0 == access(home,READ_ACCESS)) {
/* WARNING: add_dir_vector does not allocate strings --
* it just assign pointers!
*/
char * str = safe_strdup(home);
int l = strlen(str);
if (str[l-1] != '/')
str = strmcat(str,"/");
add_dir_vector(dir,str,new_string2(system_charset,s2us("~")),
BROWSER_NOFOLDER);
}
}
static int browser_change_up_dummy P_((struct folder_browser *dir,
struct string **dispname));
static int browser_change_up_dummy(dir,dispname)
struct folder_browser *dir;
struct string **dispname;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,"browser_change_up_dummy: dir=%p\n", dir));
if (dir->a.dummy_browser.remote) {
/* Deselect remote mode ... */
DPRINT(Debug,11,(&Debug,
"browser_change_up_dummy: Deselecting remote mode...\n"));
free(dir->a.dummy_browser.remote);
dir->a.dummy_browser.remote = NULL;
ret = -1;
} else {
int L = string_len(dir->dirname);
int L1 = -1;
int idx;
for (idx = 0; idx < L ; idx++) {
uint16 code = give_unicode_from_string(dir->dirname,idx);
if (0x002F /* '/' */ == code)
L1 = idx;
}
if (L1 < L-1)
L1++;
if (0 == L1) {
ret = -1;
} else {
int X = 0;
struct string * A1 = clip_from_string(dir->dirname,&X,L1);
if (*dispname)
free_string(dispname);
*dispname = A1;
ret = 1;
}
}
DPRINT(Debug,11,(&Debug,"browser_change_up_dummy=%d\n", ret));
return ret;
}
static int browser_change_dummy P_((struct folder_browser *dir,
struct string *rel_dirname,
struct string **dispname));
static int browser_change_dummy(dir,rel_dirname,dispname)
struct folder_browser *dir;
struct string *rel_dirname;
struct string **dispname;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,"browser_change_dummy: dir=%p\n", dir));
if (rel_dirname) {
DPRINT(Debug,11,(&Debug,"browser_change_dummy: rel_dirname=%S\n",
rel_dirname));
} else {
DPRINT(Debug,11,(&Debug,"browser_change_dummy: rel_dirname=NULL\n"));
}
if (dir->a.dummy_browser.remote) { /* Do not change menu */
switch(dir->sel_type) {
case selection_file:
DPRINT(Debug,11,(&Debug,
"browser_change_dummy: File browser does not support remote directories\n"));
break;
case selection_folder:
#ifdef REMOTE_MBX
/* On that point dir->a.dummy_browser.remote is user@host
indicating of POP or IMAP mailbox.
But if user requires directory content from that it
must be IMAP server directory then.
*/
if (dummy_to_imap(dir)) {
ret = dir->type->browser_change_it(dir,rel_dirname,dispname);
goto clean;
}
#endif /* REMOTE_MBX */
break;
}
lib_error(CATGETS(elm_msg_cat, MeSet, MeRemoteDirNotAvail,
"Remote directries are not available in %s"),
dir->a.dummy_browser.remote);
} else if (rel_dirname &&
string_len(rel_dirname) > 0) {
/* Menu on case where there is no DIROPS ... */
/* Dummy operation ... but for consistency ... */
struct string * relative = browser_descend_dummy(dir,rel_dirname);
struct string * Lstr = convert_string(local_fs_charset,rel_dirname,0);
unsigned char * str = stream_from_string(Lstr,0,NULL);
struct stat buf;
if (relative)
free_string(&relative);
DPRINT(Debug,12,(&Debug,
"browser_change_dummy: Trying stat %s\n",
str));
if (0 != stat(us2s(str),&buf)) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, MeSet, MeDirError,
"Directory %S: %s"),
Lstr, error_description(err));
#ifdef S_ISDIR
} else if (!S_ISDIR(buf.st_mode)) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeNoDirError,
"Not a directory: %S"),
Lstr);
#endif
} else {
ret = 1;
/* Make empty selection folder */
clear_dir_vector(dir);
if (dir->dirname)
free_string(&dir->dirname);
/* Copy just from edit buffer */
dir->dirname = dup_string(*dispname);
if (dir->sys_dir) {
free(dir->sys_dir);
dir->sys_dir = NULL;
}
dir->sys_dir = us2s(str);
str = NULL;
}
if (Lstr)
free_string(&Lstr);
if (str)
free(str);
} else { /* Default menu */
ret = 1;
browser_gen_default_menu(dir);
}
#ifdef REMOTE_MBX
clean:
#endif
DPRINT(Debug,11,(&Debug,"browser_change_dummy=%d\n", ret));
return ret;
}
int browser_select_generic(dir,relative_path,
rel_dirname,relative,Lstr,str,sep,default_charset)
struct folder_browser *dir;
struct string * relative_path;
CONST struct string * rel_dirname;
struct string * relative;
struct string ** Lstr;
char ** str;
int sep;
charset_t default_charset;
{
int ret = -1;
int i;
int l1 = dir->sys_dir ? strlen(dir->sys_dir) : 0;
int add_sep = 0;
DPRINT(Debug,12,(&Debug,"browser_select_generic: dir=%p\n",
dir));
if (!relative) {
DPRINT(Debug,12,(&Debug,
"browser_select_generic: 'relative' (to directory) name is not given, using 'rel_dirname' (to service)\n"));
goto recover;
}
if (sep == '\0' && l1 > 0) {
DPRINT(Debug,12,(&Debug,
"browser_select_generic: Separator not given!\n"));
goto recover;
}
if (l1 > 0 && sep != dir->sys_dir[l1-1]) {
add_sep = 1;
}
if (0 == string_len(relative)) {
DPRINT(Debug,12,(&Debug,
"browser_select_generic: 'relative' is empty -- directory prefix is given\n"));
ret = -2;
if (! dir->sys_dir)
goto recover;
*Lstr = dup_string(relative_path);
if (add_sep)
fill_ascii_to_string(*Lstr,1,sep);
*str = safe_strdup(dir->sys_dir);
if (add_sep) {
char buf[2];
buf[0] = sep;
buf[1] = '\0';
*str = strmcat(*str,buf);
}
DPRINT(Debug,12,(&Debug,
"browser_select_generic: Using name %s (%S) from prefix, separator %c\n",
*str,*Lstr,sep));
goto done;
}
/* Update cache ... */
browser_vector_len(dir);
for (i = 0; i < dir->vector_len; i++)
if (0 == (string_cmp(relative,
dir->vector[i].disp_name,
-99 /* Unknown indicator */)))
break;
if (i < dir->vector_len) {
if (dir->sys_dir) {
struct string * XX;
*Lstr = dup_string(relative_path);
if (add_sep)
fill_ascii_to_string(*Lstr,1,sep);
XX = *Lstr;
*Lstr = cat_strings(XX,dir->vector[i].disp_name,0);
free_string(&XX);
*str = safe_strdup(dir->sys_dir);
if (add_sep) {
char buf[2];
buf[0] = sep;
buf[1] = '\0';
*str = strmcat(*str,buf);
}
*str = strmcat(*str,dir->vector[i].sys_name);
} else {
*Lstr = dup_string(dir->vector[i].disp_name);
*str = safe_strdup(dir->vector[i].sys_name);
}
ret = i;
DPRINT(Debug,12,(&Debug,
"browser_select_generic: Using name %s (%S) from listing, separator %c\n",
*str,*Lstr,sep));
} else {
recover:
*Lstr = convert_string(default_charset,rel_dirname,0);
*str = us2s(stream_from_string(*Lstr,0,NULL));
DPRINT(Debug,12,(&Debug,
"browser_select_generic: Using system name %s (%S)\n",
*str,*Lstr));
if (rel_dirname)
DPRINT(Debug,11,(&Debug," ... rel_dirname was %S\n",
rel_dirname));
}
if (relative_path && relative)
DPRINT(Debug,12,(&Debug,
" ... relative path was %S and item %S\n",
relative_path,relative));
done:
DPRINT(Debug,12,(&Debug,"browser_select_generic=%d %s\n",
ret,
ret < 0 ? "(no index)" : "(index of listing)"));
return ret;
}
/* rel_itemname is relative to type -- not include user@hostname
rel_itemname is NULL is idicating that selection is on
dir->a.dummy_browser.remote
*/
int real_select_local(dir,rel_itemname,relative)
struct folder_browser *dir;
CONST struct string *rel_itemname;
struct string * relative;
{
struct string * Lstr = NULL;
char * str = NULL;
int F = 0;
struct stat bufX, *buf = NULL; /* stat command */
int idx;
/* give_dt_estr_as_str adds / to end */
char * folders_val = give_dt_estr_as_str(&folders_e,"maildir");
char * mbx_dir = give_dt_estr_as_str(&extra_mailbox_dir_e,
"extra-mailbox-dir");
idx = browser_select_generic(dir,dir->dirname,
rel_itemname,relative,&Lstr,&str,'/',
local_fs_charset);
if (0 == stat(str,&bufX)) {
DPRINT(Debug,11,(&Debug,
"real_select_local: %s exists\n",
str));
F = BROWSER_EXIST;
buf = &bufX;
} else {
DPRINT(Debug,11,(&Debug,
"real_select_local: %s : stat fail\n",
str));
}
if (in_directory(buf,str,mailhome))
F |= BROWSER_MAILFILE;
else if (mbx_dir &&
in_directory(buf,str,mbx_dir))
F |= BROWSER_MAILFILE;
else if (folders_val &&
in_directory(buf,str,folders_val))
F |= BROWSER_MAILFILE;
if (idx >= 0) {
DPRINT(Debug,11,(&Debug,
"real_select_local: Using index %d: %s\n",
idx,dir->vector[idx].sys_name));
if (dir->vector[idx].flags & BROWSER_NEEDSTAT) {
DPRINT(Debug,11,(&Debug,
"real_select_local: Updating flags -- doing stat\n"));
dir->type->browser_stat_routine(dir,idx);
}
/* WARNING: set_dir_selection does not allocate strings --
* it just assign pointers!
*/
set_dir_selection(dir,
safe_strdup(dir->vector[idx].sys_name),
dup_string(dir->vector[idx].disp_name),
dir->vector[idx].flags|F);
} else {
struct string * ConvRelative = convert_string(local_fs_charset,
relative,0);
char * rel_str = us2s(stream_from_string(ConvRelative,0,NULL));
DPRINT(Debug,11,(&Debug,
"real_select_local: Using given name: %s\n",
rel_str));
if (-2 == idx) {
DPRINT(Debug,11,(&Debug,
"real_select_local: Directory prefix was given.\n"));
F |= BROWSER_DIRPREFIX;
}
/* WARNING: set_dir_selection does not allocate strings --
* it just assign pointers!
*/
set_dir_selection(dir,rel_str,dup_string(relative),0|F);
free_string(&ConvRelative);
}
if (Lstr)
free_string(&Lstr);
if (str)
free(str);
DPRINT(Debug,12,(&Debug,
"real_select_local=1 dir=%p\n",
dir));
return 1;
}
static int browser_select_dummy P_((struct folder_browser *dir,
const struct string *rel_itemname,
struct string **dispname));
static int browser_select_dummy(dir,rel_itemname,dispname)
struct folder_browser *dir;
CONST struct string *rel_itemname;
struct string **dispname;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,"browser_select_dummy: dir=%p\n", dir));
if (rel_itemname) {
DPRINT(Debug,11,(&Debug,"browser_select_dummy: rel_itemname=%S\n",
rel_itemname));
} else {
DPRINT(Debug,11,(&Debug,"browser_select_dummy: rel_itemname=NULL\n"));
}
if (dir->a.dummy_browser.remote) { /* Do not change menu */
switch(dir->sel_type) {
case selection_file:
DPRINT(Debug,11,(&Debug,
"browser_change_dummy: File browser does not support remote directories\n"));
lib_error(CATGETS(elm_msg_cat, MeSet, MeRemoteFileNotAvail,
"Remote file is not available in %s"),
dir->a.dummy_browser.remote);
break;
case selection_folder:
#ifdef REMOTE_MBX
/* On that point dir->a.dummy_browser.remote is user@host
indicating of POP or IMAP mailbox.
But if rel_itemname is non-NULL, then it must be on
IMAP server directory...
*/
if (rel_itemname) {
/* IMAP directory then ... */
if (dummy_to_imap(dir)) {
ret = dir->type->browser_select_it(dir,rel_itemname,
dispname);
goto clean;
}
} else {
/* Assume OK */
/* Null selection when remote mode ... */
set_dir_selection(dir,NULL,NULL,
BROWSER_EXIST /* Assume existance */
|BROWSER_MAILFILE /* Assume folder */
);
ret = 1;
goto clean;
}
#endif /* REMOTE_MBX */
lib_error(CATGETS(elm_msg_cat, MeSet, MeRemoteFolderNotAvail,
"Remote folder is not available in %s"),
dir->a.dummy_browser.remote);
break;
}
} else if (rel_itemname) {
/* Make selection relative ... */
struct string * relative = browser_descend_dummy(dir,rel_itemname);
if (relative) {
ret = real_select_local(dir,rel_itemname,relative);
free_string(&relative);
}
}
#ifdef REMOTE_MBX
clean:
#endif
DPRINT(Debug,11,(&Debug,"browser_select_dummy=%d\n", ret));
return ret;
}
static struct string * browser_give_title_dummy P_((struct folder_browser *dir));
static struct string * browser_give_title_dummy(dir)
struct folder_browser *dir;
{
static struct string *ret;
DPRINT(Debug,11,(&Debug,"browser_give_title_dummy: dir=%p\n", dir));
if (dir->dirname)
ret = format_string(CATGETS(elm_msg_cat, MeSet,MeNoDirListing,
"Directory listing for %S not available"),
dir->dirname);
else
ret = format_string(CATGETS(elm_msg_cat, MeSet,MeDefaultDir,
"Default directory"));
DPRINT(Debug,11,(&Debug,"browser_give_title_dummy=%S\n", ret));
return ret;
}
static char browser_separator_dummy P_((struct folder_browser *dir));
static char browser_separator_dummy(dir)
struct folder_browser *dir;
{
if (dir->a.dummy_browser.remote)
return '\0';
else
return '/';
}
static struct string * browser_name_dummy P_((struct folder_browser *dir));
static struct string * browser_name_dummy(dir)
struct folder_browser *dir;
{
static struct string *ret;
DPRINT(Debug,11,(&Debug,"browser_name_dummy: dir=%p\n",
dir));
if (dir->a.dummy_browser.remote) {
ret = format_string(CATGETS(elm_msg_cat, MeSet,MeRemoteServer,
"Remote server %s"),
dir->a.dummy_browser.remote);
} else if (dir->dirname) {
ret = format_string(CATGETS(elm_msg_cat, MeSet,MeLocalDir,
"Local directory %S"),
dir->dirname);
} else {
ret = format_string(CATGETS(elm_msg_cat, MeSet,MeDefaultDir,
"Default directory"));
}
DPRINT(Debug,11,(&Debug,"browser_name_dummy=%S\n", ret));
return ret;
}
static struct string * browser_cat_dummy P_((struct folder_browser *dir,
struct string * item));
static struct string * browser_cat_dummy(dir,item)
struct folder_browser *dir;
struct string * item;
{
struct string * ret = NULL;
int L;
DPRINT(Debug,11,(&Debug,"browser_cat_dummy: dir=%p\n",
dir));
if (dir->a.dummy_browser.remote) {
switch(dir->sel_type) {
case selection_file:
DPRINT(Debug,11,(&Debug,
"browser_cat_dummy: File browser does not support remote directories\n"));
lib_error(CATGETS(elm_msg_cat, MeSet, MeRemoteFileNotAvail,
"Remote file is not available in %s"),
dir->a.dummy_browser.remote);
break;
case selection_folder:
#ifdef REMOTE_MBX
/* Must have IMAP folder !! */
if (dummy_to_imap(dir)) {
ret = dir->type->browser_cat_it(dir,item);
goto clean;
}
#endif
lib_error(CATGETS(elm_msg_cat, MeSet, MeRemoteFolderNotAvail,
"Remote folder is not available in %s"),
dir->a.dummy_browser.remote);
break;
}
goto clean;
}
if (dir->dirname &&
(L = string_len(dir->dirname)) > 0) {
ret = dup_string(dir->dirname);
if (L > 0 &&
0x002F /* '/' */ != give_unicode_from_string(dir->dirname,
L-1))
fill_ascii_to_string(ret,1,'/');
/* Some local directory! */
if (item) {
struct string * XX = ret;
ret = cat_strings(XX,item,0);
free_string(&XX);
}
} else {
/* Default MENU ! */
if (item)
ret = dup_string(item);
else
ret = new_string(system_charset);
}
clean:
if (ret) {
DPRINT(Debug,11,(&Debug,"browser_cat_dummy=%S\n",ret));
} else {
DPRINT(Debug,11,(&Debug,"browser_cat_dummy=NULL\n"));
}
return ret;
}
struct folder_info * real_folder_from_local(dir)
struct folder_browser *dir;
{
struct folder_info *res = NULL;
DPRINT(Debug,12,(&Debug,"real_folder_from_local: dir=%p\n", dir));
if (dir->selection->sys_name) { /* Must have local file */
enum folder_place place;
res = mbx_new_folder();
if (dir->sys_dir && dir->sys_dir[0]) {
res -> cur_folder_sys = elm_message(FRM("%s/%s"),
dir->sys_dir,
dir->selection->sys_name);
res -> cur_folder_disp = format_string(FRM("%S/%S"),
dir->dirname,
dir->selection->disp_name);
} else {
res -> cur_folder_sys = safe_strdup(dir->selection->sys_name);
res -> cur_folder_disp = dup_string(dir->selection->disp_name);
}
res-> folder_type = get_folder_type(res -> cur_folder_sys,&place);
switch (place) {
case in_home:
free_string(&(res -> cur_folder_disp));
res -> cur_folder_disp = format_string(FRM("~/%S"),
dir->selection->disp_name);
break;
case in_folders:
free_string(&(res -> cur_folder_disp));
res -> cur_folder_disp = format_string(FRM("=%S"),
dir->selection->disp_name);
break;
}
res-> folder_type->init_it(res);
}
if (res) {
DPRINT(Debug,12,(&Debug,"real_folder_from_local=%p\n",res));
} else {
DPRINT(Debug,12,(&Debug,"real_folder_from_local=NULL\n"));
}
return res;
}
static struct folder_info *
browser_folder_from_dummy P_((struct folder_browser *dir));
static struct folder_info * browser_folder_from_dummy(dir)
struct folder_browser *dir;
{
struct folder_info * res = NULL;
DPRINT(Debug,11,(&Debug,"browser_folder_from_dummy: dir=%p\n",
dir));
if (dir->sel_type != selection_folder)
panic("BROWSER PANIC",__FILE__,__LINE__,
"browser_folder_from_dummy",
"Bad selection type",0);
if (dir->a.dummy_browser.remote) {
#ifdef REMOTE_MBX
if (dir->selection->sys_name) {
/* Must have IMAP folder !! */
if (dummy_to_imap(dir)) {
res = dir->type->browser_folder_from_it(dir);
goto clean;
}
} else {
struct remote_account X;
struct service_entry *se = NULL;
char *rest = NULL;
int code;
zero_remote_account(&X);
/* -1 == name not found or bad syntax
0 == not a remote address
1 == name found
*/
if (0 <= (code = split_remote_name(dir->a.dummy_browser.remote,
&X,&se,&rest,
0 /* Both POP and IMAP are OK */
))) {
if (code == 0 || rest)
panic("BROWSER PANIC",__FILE__,__LINE__,
"browser_folder_from_dummy",
"Bad return from split_remote_name",0);
res = mbx_new_folder();
res -> cur_folder_sys =
safe_strdup(dir->a.dummy_browser.remote);
res -> cur_folder_disp =
new_string2(display_charset,
s2us(dir->a.dummy_browser.remote));
/* May free X (if succeed) or copy
If make copy of X, then X is zeroed
*/
if (!make_remote_mbox(res,&X,se,NULL,1)) {
res -> folder_type = NO_NAME;
res->folder_type->init_it(res);
}
free_temporary_service_entry(&se);
free_remote_account(&X);
goto clean;
}
free_temporary_service_entry(&se);
free_remote_account(&X);
}
#endif
lib_error(CATGETS(elm_msg_cat, MeSet, MeRemoteFolderNotAvail,
"Remote folder is not available in %s"),
dir->a.dummy_browser.remote);
} else
res = real_folder_from_local(dir);
#ifdef REMOTE_MBX
clean:
#endif
if (res) {
DPRINT(Debug,11,(&Debug,"browser_folder_from_dummy=%p\n",res));
} else {
DPRINT(Debug,11,(&Debug,"browser_folder_from_dummy=NULL\n"));
}
return res;
}
int real_selection_is_local(dir,folder)
struct folder_browser *dir;
struct folder_info *folder;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,"real_selection_is_local: dir=%p\n",
dir));
if (folder->folder_type != &read_only &&
folder->folder_type != &non_spool &&
folder->folder_type != &spool) {
DPRINT(Debug,11,(&Debug,
"real_selection_is_local: Not a local folder\n"));
ret = 0;
} else {
char * name;
if (dir->sys_dir && dir->sys_dir[0])
name = elm_message(FRM("%s/%s"),
dir->sys_dir,
dir->selection->sys_name);
else
name = safe_strdup(dir->selection->sys_name);
if (0 == strcmp(name,folder->cur_folder_sys)) {
DPRINT(Debug,11,(&Debug,
"real_selection_is_local: Same filaname\n"));
ret = 1;
} else {
struct stat XX, A;
if (-1 == stat(name,&A)) {
int err = errno;
DPRINT(Debug,11,(&Debug,
"real_selection_is_local: Failed to stat %s: %s\n",
name,
error_description(err)));
err = 0;
} else if ((NULL != folder ->p->fh_folder &&
0 == fstat(fileno(folder ->p->fh_folder),&XX))
||
0 == stat(folder->cur_folder_sys,&XX)) {
if (XX.st_ino == A.st_ino && XX.st_dev == A.st_dev) {
DPRINT(Debug,11,(&Debug,
"real_selection_is_local: Same ino and dev\n"));
ret = 1;
} else
ret = 0;
} else {
int err = errno;
DPRINT(Debug,11,(&Debug,
"real_selection_is_local: Both fstat and stat failed: %s\n",
error_description(err)));
ret = 0;
}
}
if (name)
free(name);
}
DPRINT(Debug,11,(&Debug,"real_selection_is_local=%d\n",ret));
return ret;
}
static int browser_selection_is_dummy P_((struct folder_browser *dir,
struct folder_info *folder));
static int browser_selection_is_dummy(dir,folder)
struct folder_browser *dir;
struct folder_info *folder;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,"browser_selection_is_dummy: dir=%p\n",
dir));
if (dir->sel_type != selection_folder)
panic("BROWSER PANIC",__FILE__,__LINE__,
"browser_selection_is_dummy",
"Bad selection type",0);
if (dir->a.dummy_browser.remote) {
#ifdef REMOTE_MBX
if (folder->folder_type == POP_MBX) {
DPRINT(Debug,11,(&Debug,
"browser_selection_is_dummy: Maybe POP ...\n"));
ret = 0 == strcmp(dir->a.dummy_browser.remote,
folder->cur_folder_sys);
} else if (folder->folder_type == IMAP_MBX) {
DPRINT(Debug,11,(&Debug,
"browser_selection_is_dummy: Maybe IMAP ...\n"));
if (dummy_to_imap(dir)) {
ret = dir->type->browser_selection_is_it(dir,folder);
} else {
DPRINT(Debug,11,(&Debug,
"browser_selection_is_dummy: IMAP failed\n"));
ret = 0;
}
} else {
DPRINT(Debug,11,(&Debug,
"browser_selection_is_dummy: Folder is not remote\n"));
ret = 0;
}
#else
DPRINT(Debug,11,(&Debug,
"browser_selection_is_dummy: Remote selection is not available\n"));
ret = 0;
#endif
} else {
ret = real_selection_is_local(dir,folder);
}
DPRINT(Debug,11,(&Debug,
"browser_selection_is_dummy=%d\n",ret));
return ret;
}
int create_as_user(name)
CONST char *name;
{
int the_stat = 0, pid, w, sig;
VOLATILE int ret = 0;
S__ status;
if ((pid =
#ifdef VFORK
vfork()
#else
fork()
#endif
) == 0) {
int filedes;
if (-1 == setgid(groupid)) {
int err = errno;
fprintf(stderr,"create_as_user: setgid(%d) FAILED: %s\n",
groupid,error_description(err));
fflush(stderr);
_exit(err != 0? err : 1); /* never return zero! */
}
if (-1 == setuid(userid)) { /** back to normal userid **/
int err = errno;
fprintf(stderr,"create_as_user: setuid(%d) FAILED: %s\n",
userid,error_description(err));
fflush(stderr);
_exit(err != 0? err : 1); /* never return zero! */
}
errno = 0;
filedes = open(name, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (filedes < 0)
_exit(errno);
else {
close(filedes);
_exit(0);
}
}
errno = 0;
while ((w = my_wait(pid,&status)) != pid &&
(w != -1 || EINTR == errno))
;
sig = convert_status(status,&the_stat);
if (sig)
ret = 0;
else if (0 == the_stat)
ret = 1;
else
lib_error(CATGETS(elm_msg_cat, MeSet, MeCreatingFileFailed,
"Creating of file %s failed: %s"),
name,error_description(the_stat));
return ret;
}
static int browser_create_selection_dummy P_((struct folder_browser *dir));
static int browser_create_selection_dummy(dir)
struct folder_browser *dir;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,
"browser_create_selection_dummy: dir=%p\n",
dir));
if (dir->a.dummy_browser.remote) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeCreatingRemoteFolderNotSupp,
"Creating of remote folder for %s not supported"),
dir->a.dummy_browser.remote);
} else {
char * name = NULL;
if (dir->sys_dir && dir->sys_dir[0])
name = elm_message(FRM("%s/%s"),
dir->sys_dir,
dir->selection->sys_name);
else
name = safe_strdup(dir->selection->sys_name);
ret = create_as_user(name);
free(name);
}
DPRINT(Debug,11,(&Debug,"browser_create_selection_dummy=%d\n", ret));
return ret;
}
/* We use same routines zero_ws_fields_local and free_ws_fields_local
* both dummy and local browser!
*/
void zero_ws_fields_local(ptr)
WRITE_STATE ptr;
{
ptr->a.local.save_fd = -1;
ptr->a.local.save_file = NULL;
}
void free_ws_fields_local(ptr)
WRITE_STATE ptr;
{
/* ptr->a.local.save_file and ptr->a.local.save_fd shares same
file descriptor!
*/
if (ptr->a.local.save_file) {
fclose(ptr->a.local.save_file);
ptr->a.local.save_file = NULL;
ptr->a.local.save_fd = -1;
}
if (-1 != ptr->a.local.save_fd) {
close(ptr->a.local.save_fd);
ptr->a.local.save_fd = -1;
}
}
int real_prepare_write_local(dir,ptr,filename)
struct folder_browser *dir;
WRITE_STATE ptr;
CONST char *filename;
{
int ret = 0;
int err = 0;
switch(dir->sel_type) {
case selection_file:
if (0 != (err = can_open(filename, "w"))) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeCouldnWriteFile,
"Couldn't write to file %s: %s"),
filename,error_description(err));
goto fail;
}
DPRINT(Debug,4,(&Debug,"Writing to file '%s'...\n", filename));
if ((ptr->a.local.save_fd = open(filename,O_WRONLY,0600)) == -1 ||
(ptr->a.local.save_file = fdopen(ptr->a.local.save_fd,"w")) == NULL) {
int err = errno;
DPRINT(Debug,2,(&Debug,
"Error: couldn't write to specified file %s\n",
filename));
lib_error(CATGETS(elm_msg_cat, MeSet, MeCouldnWriteFile,
"Couldn't write to file %s: %s"),
filename,error_description(err));
goto fail;
}
ret = 1;
break;
case selection_folder:
if (0 != (err = can_open(filename, "a"))) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeCouldntAppendFolder,
"Couldn't append to folder %s: %s"),
filename,error_description(err));
goto fail;
}
save_file_stats(filename);
DPRINT(Debug,4,(&Debug, "Saving mail to folder '%s'...\n", filename));
if ((ptr->a.local.save_fd = open(filename,O_RDWR,0600)) == -1 ||
(ptr->a.local.save_file = fdopen(ptr->a.local.save_fd,"r+")) == NULL) {
int err = errno;
DPRINT(Debug,2,(&Debug,
"Error: couldn't append to specified folder %s\n",
filename));
lib_error(CATGETS(elm_msg_cat, MeSet, MeCouldntAppendFolder,
"Couldn't append to folder %s: %s"),
filename,error_description(err));
goto fail;
}
if (lock_in_copy) {
/* lock the file to be modified to serialize access with other */
/* programs like procmail. */
if (Grab_the_file(ptr->a.local.save_fd) != FLOCKING_OK){
int err = errno;
fclose(ptr->a.local.save_file);
ptr->a.local.save_file = NULL;
ptr->a.local.save_fd = -1;
restore_file_stats(filename);
DPRINT(Debug,2,(&Debug,
"Error: couldn't lock specified folder %s (save)\n",
filename));
lib_error(CATGETS(elm_msg_cat, MeSet, MeCouldntLockFolder,
"Couldn't lock folder %s: %s"),
filename,
error_description(err));
goto fail;
}
}
/* copy_message want now seek backwards ... */
if (0 != fseek(ptr->a.local.save_file,0,SEEK_END)) {
int err = errno;
if (lock_in_copy)
Release_the_file(ptr->a.local.save_fd);
ptr->a.local.save_file = NULL;
ptr->a.local.save_fd = -1;
restore_file_stats(filename);
DPRINT(Debug,2,(&Debug,
"Error: couldn't seek to end of specified folder %s (save)\n",
filename));
lib_error(CATGETS(elm_msg_cat, MeSet, MeCouldntAppendFolder,
"Couldn't append to folder %s: %s"),
filename,error_description(err));
goto fail;
}
ret = 1;
break;
}
fail:
DPRINT(Debug,12,(&Debug,
"real_prepare_write_local=%d dir=%p filename=%s\n",
ret,dir,filename));
return ret;
}
int real_end_write_local(dir,ptr,filename)
struct folder_browser *dir;
WRITE_STATE ptr;
CONST char *filename;
{
int ret = 0;
if (lock_in_copy)
Release_the_file(ptr->a.local.save_fd); /* XXX LOCKING */
/** ptr->a.local.save_file and ptr->a.local.save_fd shares same
file descriptor!
*/
ret = 0 == fclose(ptr->a.local.save_file);
ptr->a.local.save_file = NULL;
ptr->a.local.save_fd = -1;
switch(dir->sel_type) {
case selection_file:
break;
case selection_folder:
restore_file_stats(filename);
break;
}
DPRINT(Debug,12,(&Debug,
"real_end_write_local=%d dir=%p filename=%s\n",
ret,dir,filename));
return ret;
}
int real_sync_write_local(dir,ptr,filename)
struct folder_browser *dir;
WRITE_STATE ptr;
CONST char *filename;
{
int ret = 0;
/** ptr->a.local.save_file and ptr->a.local.save_fd shares same
file descriptor!
*/
ret = 0 == fflush(ptr->a.local.save_file);
if (!ret) {
DPRINT(Debug,12,(&Debug,
"real_sync_write_local: fflush failed\n"));
}
if (-1 == fsync(ptr->a.local.save_fd)) {
DPRINT(Debug,12,(&Debug,
"real_sync_write_local: fsync failed\n"));
ret = 0;
}
switch(dir->sel_type) {
case selection_file:
break;
case selection_folder:
break;
}
DPRINT(Debug,12,(&Debug,
"real_sync_write_local=%d dir=%p filename=%s\n",
ret,dir,filename));
return ret;
}
long real_browser_tell_ws(dir,ptr)
struct folder_browser *dir;
WRITE_STATE ptr;
{
/* Both ftell and real_browser_tell_ws returns -1 on failure */
long ret = ftell(ptr->a.local.save_file);
if (-1 == ret) {
int err = errno;
DPRINT(Debug,12,(&Debug,
"real_browser_tell_ws: ERROR (errno=%d): %s\n",
err,error_description(err)));
}
DPRINT(Debug,12,(&Debug,
"real_browser_tell_ws=%ld dir=%p\n",
ret,dir));
return ret;
}
/* Returns 0 on failure! */
int real_browser_seek_ws(dir,ptr,pos)
struct folder_browser *dir;
WRITE_STATE ptr;
long pos;
{
int ret = 0;
if (0 == fseek(ptr->a.local.save_file,pos,SEEK_SET))
ret = 1;
else {
int err = errno;
DPRINT(Debug,12,(&Debug,
"real_browser_seek_ws: ERROR (errno=%d): %s\n",
err,error_description(err)));
}
DPRINT(Debug,12,(&Debug,
"real_browser_seek_ws=%d dir=%p\n",
ret,dir));
return ret;
}
int real_browser_write_ws(dir,ptr,l,buffer)
struct folder_browser *dir;
WRITE_STATE ptr;
int l;
CONST char *buffer;
{
int ret = 1;
int count = 0;
while (ret && count < l) {
int x = fwrite(buffer+count,1,l-count,ptr->a.local.save_file);
if (x > 0)
count += x;
else if (ferror(ptr->a.local.save_file)) {
int err = errno;
if (err != EINTR) {
DPRINT(Debug,12,(&Debug,
"real_browser_write_ws: ERROR (errno=%d): %s\n",
err,error_description(err)));
ret = 0;
} else {
clearerr(ptr->a.local.save_file);
}
}
if (0 == x && ret) {
DPRINT(Debug,12,(&Debug,
"real_browser_write_ws: Looping...\n"));
}
}
DPRINT(Debug,12,(&Debug,
"real_browser_write_ws=%d dir=%p (%d written of %d)\n",
ret,dir,count,l));
return ret;
}
static int browser_prepare_write_dummy P_((struct folder_browser *dir,
WRITE_STATE ptr));
static int browser_prepare_write_dummy(dir,ptr)
struct folder_browser *dir;
WRITE_STATE ptr;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,"browser_prepare_write_dummy: dir=%p\n",
dir));
if (dir->a.dummy_browser.remote) {
switch(dir->sel_type) {
case selection_file:
DPRINT(Debug,11,(&Debug,
"browser_prepare_write_dummy: File browser does not support remote directories\n"));
lib_error(CATGETS(elm_msg_cat, MeSet, MeWritingRemoteFileNotSupp,
"Writing to remote file %s not supported"),
dir->a.dummy_browser.remote);
break;
case selection_folder:
#ifdef REMOTE_MBX
/* Must have IMAP folder !! */
dir->type->free_ws_fields_it(ptr); /* Need reinit of state */
if (dummy_to_imap(dir)) {
dir->type->zero_ws_fields_it(ptr); /* Hopefully ok ....... */
ret = dir->type->browser_prepare_write_it(dir,ptr);
goto clean;
}
#endif /* REMOTE_MBX */
lib_error(CATGETS(elm_msg_cat, MeSet, MeWritingRemoteFolderNotSupp,
"Writing to remote folder %s not supported"),
dir->a.dummy_browser.remote);
break;
}
} else {
char * name = NULL;
if (dir->sys_dir && dir->sys_dir[0])
name = elm_message(FRM("%s/%s"),
dir->sys_dir,
dir->selection->sys_name);
else
name = safe_strdup(dir->selection->sys_name);
ret = real_prepare_write_local(dir,ptr,name);
free(name);
}
#ifdef REMOTE_MBX
clean:
#endif
DPRINT(Debug,11,(&Debug,"browser_prepare_write_dummy=%d\n", ret));
return ret;
}
static int browser_sync_write_dummy P_((struct folder_browser *dir,
WRITE_STATE ptr));
static int browser_sync_write_dummy(dir,ptr)
struct folder_browser *dir;
WRITE_STATE ptr;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,"browser_sync_write_dummy: dir=%p\n",
dir));
if (dir->a.dummy_browser.remote) {
panic("BROWSER PANIC",__FILE__,__LINE__,
"browser_sync_write_dummy",
"Bad remote argument",0);
} else {
char * name = NULL;
if (dir->sys_dir && dir->sys_dir[0])
name = elm_message(FRM("%s/%s"),
dir->sys_dir,
dir->selection->sys_name);
else
name = safe_strdup(dir->selection->sys_name);
ret = real_sync_write_local(dir,ptr,name);
free(name);
}
DPRINT(Debug,11,(&Debug,"browser_sync_write_dummy=%d\n", ret));
return ret;
}
static int browser_end_write_dummy P_((struct folder_browser *dir,
WRITE_STATE ptr));
static int browser_end_write_dummy(dir,ptr)
struct folder_browser *dir;
WRITE_STATE ptr;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,"browser_end_write_dummy: dir=%p\n",
dir));
if (dir->a.dummy_browser.remote) {
panic("BROWSER PANIC",__FILE__,__LINE__,
"browser_end_write_dummy",
"Bad remote argument",0);
} else {
char * name = NULL;
if (dir->sys_dir && dir->sys_dir[0])
name = elm_message(FRM("%s/%s"),
dir->sys_dir,
dir->selection->sys_name);
else
name = safe_strdup(dir->selection->sys_name);
ret = real_end_write_local(dir,ptr,name);
free(name);
}
DPRINT(Debug,11,(&Debug,"browser_end_write_dummy=%d\n", ret));
return ret;
}
static long browser_tell_dummy_ws P_((struct folder_browser *dir,
WRITE_STATE write_state_ptr));
static long browser_tell_dummy_ws(dir,write_state_ptr)
struct folder_browser *dir;
WRITE_STATE write_state_ptr;
{
long ret = -1L;
DPRINT(Debug,11,(&Debug,"browser_tell_dummy_ws: dir=%p\n",
dir));
if (dir->a.dummy_browser.remote) {
panic("BROWSER PANIC",__FILE__,__LINE__,
"browser_tell_dummy_ws",
"Bad remote argument",0);
}
ret = real_browser_tell_ws(dir,write_state_ptr);
DPRINT(Debug,11,(&Debug,"browser_tell_dummy_ws=%ld\n",ret));
return ret;
}
/* Returns 0 on failure */
static int browser_seek_dummy_ws P_((struct folder_browser *dir,
WRITE_STATE write_state_ptr,
long pos));
static int browser_seek_dummy_ws(dir,write_state_ptr,pos)
struct folder_browser *dir;
WRITE_STATE write_state_ptr;
long pos;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,"browser_seek_dummy_ws: dir=%p\n",
dir));
if (dir->a.dummy_browser.remote) {
panic("BROWSER PANIC",__FILE__,__LINE__,
"browser_seek_dummy_ws",
"Bad remote argument",0);
}
ret = real_browser_seek_ws(dir,write_state_ptr,pos);
DPRINT(Debug,11,(&Debug,"browser_seek_dummy_ws=%d\n",ret));
return ret;
}
static int browser_write_dummy_ws P_((struct folder_browser *dir,
WRITE_STATE ptr,
int l, const char *buffer));
static int browser_write_dummy_ws(dir,ptr,l,buffer)
struct folder_browser *dir;
WRITE_STATE ptr;
int l;
CONST char *buffer;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,"browser_write_dummy_ws: dir=%p\n",
dir));
if (dir->a.dummy_browser.remote) {
panic("BROWSER PANIC",__FILE__,__LINE__,
"browser_write_dummy_ws",
"Bad remote argument",0);
}
ret = real_browser_write_ws(dir,ptr,l,buffer);
DPRINT(Debug,11,(&Debug,"browser_write_dummy_ws=%d\n",ret));
return ret;
}
int real_start_we_local(dir,ptr,current_header,env_flags)
struct folder_browser *dir;
WRITE_STATE ptr;
struct header_rec *current_header;
int *env_flags;
{
int ret = 0;
char * buffer1 = ctime(& current_header->received_time);
*env_flags = 0;
#ifdef MMDF
DPRINT(Debug,5,(&Debug,
"real_start_we_local: Write MMDF message separator\n"));
if (fprintf(ptr->a.local.save_file, "%s", MSG_SEPARATOR) == EOF) {
DPRINT(Debug,1,(&Debug, "real_start_we_local fails\n"));
goto fail;
}
*env_flags = WE_ADD_RETURN_PATH;
#endif
if (fprintf(ptr->a.local.save_file,
"From %s %.24s\n",
current_header->env_from,
buffer1) == EOF) {
DPRINT(Debug,1,(&Debug,"real_start_we_local fails\n"));
goto fail;
}
ret = 1;
fail:
DPRINT(Debug,12,(&Debug,
"real_start_we_local=%d dir=%p\n",
ret,dir));
return ret;
}
int real_end_we_local(dir,ptr,current_header)
struct folder_browser *dir;
WRITE_STATE ptr;
struct header_rec *current_header;
{
int ret = 0;
long END_pos = ftell(ptr->a.local.save_file);
char buffer[2];
int i;
long NEW_pos = END_pos - 2L;
/* parse_body_routine() excludes ending empty line from
content_length, so add empty line always to mail
see also mbx_mark_keep_normal() on localmbx.c
*/
buffer[0] = '\0';
buffer[1] = '\0';
if (NEW_pos < 0L)
NEW_pos = 0L;
if (0 != fseek(ptr->a.local.save_file,NEW_pos,SEEK_SET)) {
DPRINT(Debug,5,(&Debug,
"real_end_we_local: Failed to seek to %ld (output)\n",
NEW_pos));
}
i = fread(buffer,sizeof (char),2,ptr->a.local.save_file);
if (i < 0) {
DPRINT(Debug,5,(&Debug,
"real_end_we_local: Read error! (output)\n"));
i = 0;
} else {
DPRINT(Debug,5,(&Debug,
"real_end_we_local: read %d bytes (output). \n",i));
}
for (; i < 2; i++) {
buffer[i] = '\0';
}
DPRINT(Debug,5,(&Debug,
"real_end_we_local: last two bytes %d %d (output)\n",
buffer[0], buffer[1]));
if (0 != fseek(ptr->a.local.save_file,0L,SEEK_CUR)) {
DPRINT(Debug,5,(&Debug,
"real_end_we_local: Failed to seek 0 bytes (output)\n"));
}
if (buffer[1] != '\n') {
/* No \n in end ? */
DPRINT(Debug,5,(&Debug,
"real_end_we_local: NL missing from end of mail\n"));
if (fprintf(ptr->a.local.save_file, "\n") == EOF) {
DPRINT(Debug,5,(&Debug,
"real_end_we_local: Failed to add NL to end of mail\n"));
DPRINT(Debug,1,(&Debug,"real_end_we_local fails\n"));
goto fail;
}
}
/* NOTE:
* Ending empty line or MSG_SEPARATOR is not part of
* mail, but instead part of folder format, so it
* should NOT be included on calculation of content-length
*/
#ifndef MMDF
/* blank line to keep mailx happy *sigh* */
if (fprintf(ptr->a.local.save_file, "\n") == EOF) {
DPRINT(Debug,5,(&Debug,
"real_end_we_local: Failed to add second NL to end of mail\n"));
DPRINT(Debug,1,(&Debug, "real_end_we_local fails\n"));
goto fail;
}
#else
DPRINT(Debug,5,(&Debug,
"real_end_we_local: Write MMDF message separator (end)\n"));
if (fprintf(ptr->a.local.save_file, "%s", MSG_SEPARATOR) == EOF) {
DPRINT(Debug,1,(&Debug, "real_end_we_local fails\n"));
goto fail;
}
#endif
ret = 1;
fail:
DPRINT(Debug,12,(&Debug,
"real_end_we_local=%d dir=%p\n",
ret,dir));
return ret;
}
static int browser_start_we_dummy P_((struct folder_browser *dir,
WRITE_STATE write_state_ptr,
int write_envelope,
struct header_rec *current_header,
int *env_flags));
static int browser_start_we_dummy(dir,write_state_ptr,
write_envelope,current_header,
env_flags)
struct folder_browser *dir;
WRITE_STATE write_state_ptr;
int write_envelope;
struct header_rec *current_header;
int *env_flags;
{
int ret = 1;
DPRINT(Debug,11,(&Debug,"browser_start_we_dummy: dir=%p\n",
dir));
if (dir->a.dummy_browser.remote) {
panic("BROWSER PANIC",__FILE__,__LINE__,
"browser_start_we_dummy",
"Bad remote argument",0);
}
*env_flags = 0;
if (write_envelope)
ret = real_start_we_local(dir,write_state_ptr,
current_header, env_flags);
DPRINT(Debug,11,(&Debug,"browser_start_we_dummy=%d\n",ret));
return ret;
}
static int browser_end_we_dummy P_((struct folder_browser *dir,
WRITE_STATE write_state_ptr,
int write_envelope,
struct header_rec *current_header));
static int browser_end_we_dummy(dir,write_state_ptr,
write_envelope,current_header)
struct folder_browser *dir;
WRITE_STATE write_state_ptr;
int write_envelope;
struct header_rec *current_header;
{
int ret = 1;
DPRINT(Debug,11,(&Debug,"browser_end_we_dummy: dir=%p\n",
dir));
if (dir->a.dummy_browser.remote) {
panic("BROWSER PANIC",__FILE__,__LINE__,
"browser_end_we_dummy",
"Bad remote argument",0);
}
if (write_envelope)
ret = real_end_we_local(dir,write_state_ptr,current_header);
DPRINT(Debug,11,(&Debug,"browser_end_we_dummy=%d\n",ret));
return ret;
}
int real_make_ref_local(dir,refname,iscopy,is_text)
struct folder_browser *dir;
char **refname;
int *iscopy;
int is_text;
{
char * name = NULL;
int ret = 0;
if (dir->sys_dir && dir->sys_dir[0])
name = elm_message(FRM("%s/%s"),
dir->sys_dir,
dir->selection->sys_name);
else
name = safe_strdup(dir->selection->sys_name);
if (access(name,READ_ACCESS) < 0) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, MeSet,
MeErrorRead,
"Can't read %S: %s"),
dir->selection->disp_name,error_description(err));
ret = 0;
free(name);
name = NULL;
} else {
*iscopy = 0;
*refname = name;
name = NULL;
ret = 1;
DPRINT(Debug,12,(&Debug,"real_make_ref_local: *refname=%s\n",
*refname));
}
DPRINT(Debug,12,(&Debug,"real_make_ref_local=%d", ret));
return ret;
}
static int browser_make_ref_dummy P_((struct folder_browser *dir,
char **refname, int *iscopy,
int is_text));
static int browser_make_ref_dummy(dir,refname,iscopy,is_text)
struct folder_browser *dir;
char **refname;
int *iscopy;
int is_text;
{
int ret = 0;
DPRINT(Debug,11,(&Debug,"browser_make_ref_dummy: dir=%p\n",
dir));
if (dir->sel_type != selection_file)
panic("BROWSER PANIC",__FILE__,__LINE__,
"browser_make_ref_dummy",
"Bad selection type",0);
if (dir->a.dummy_browser.remote) {
DPRINT(Debug,11,(&Debug,
"browser_make_ref_dummy: File browser does not support remote directories\n"));
lib_error(CATGETS(elm_msg_cat, MeSet, MeRemoteFileNotAvail,
"Remote file is not available in %s"),
dir->a.dummy_browser.remote);
} else {
ret = real_make_ref_local(dir,refname,iscopy,is_text);
}
DPRINT(Debug,11,(&Debug,"browser_make_ref_dummy=%d\n",ret));
return ret;
}
static void browser_update_dummy P_((struct folder_browser *dir));
static void browser_update_dummy(dir)
struct folder_browser *dir;
{
panic("BROWSER PANIC",__FILE__,__LINE__,"browser_update_dummy",
"browser_update_dummy() called",0);
}
/* Call only if BROWSER_NEEDSTAT is set */
static void browser_dummy_do_stat P_((struct folder_browser *dir,
int idx));
static void browser_dummy_do_stat(dir,idx)
struct folder_browser *dir;
int idx;
{
panic("BROWSER PANIC",__FILE__,__LINE__,"browser_dummy_do_stat",
"browser_update_dummy() called",0);
}
S_(browser_folder_sort_dir browser_folder_sort_dummy)
static void browser_folder_sort_dummy P_((struct folder_browser *dir,
print_sort_message * print));
static void browser_folder_sort_dummy(dir,print)
struct folder_browser *dir;
print_sort_message * print;
{
/* Nothing */
}
static struct browser_type dummy_browser = { browser_zero_dummy,
browser_free_dummy,
browser_change_dummy,
browser_give_title_dummy,
browser_separator_dummy,
browser_name_dummy,
browser_cat_dummy,
browser_select_dummy,
browser_folder_from_dummy,
browser_change_v_dummy,
browser_change_up_dummy,
browser_create_selection_dummy,
zero_ws_fields_local,
free_ws_fields_local,
browser_prepare_write_dummy,
browser_end_write_dummy,
browser_tell_dummy_ws,
browser_seek_dummy_ws,
browser_write_dummy_ws,
browser_start_we_dummy,
browser_end_we_dummy,
browser_selection_is_dummy,
browser_make_ref_dummy,
browser_update_dummy,
browser_dummy_do_stat,
browser_sync_write_dummy,
browser_folder_sort_dummy,
};
/* ---------------------------------------------------------------------- */
static int valid_browser P_((struct browser_type * type));
static int valid_browser(type)
struct browser_type * type;
{
if (
#ifdef REMOTE_MBX
&imap_browser == type ||
#endif
#ifdef DIROPS
&local_browser == type ||
#endif
&dummy_browser == type)
return 1;
return 0;
}
/* Folder browser */
void clear_dir_selection(dir)
struct folder_browser *dir;
{
DPRINT(Debug,12,(&Debug,
"clear_dir_selection: dir=%p; type=%p\n",
dir,dir->type));
if (dir->selection) {
if (dir->selection->sys_name) {
free(dir->selection->sys_name);
dir->selection->sys_name = NULL;
}
if (dir->selection->disp_name)
free_string(&(dir->selection->disp_name));
free(dir->selection);
dir->selection = NULL;
}
}
/* WARNING: set_dir_selection does not allocate strings --
* it just assign pointers!
*/
void set_dir_selection(dir,sys_name,disp_name,flags)
struct folder_browser *dir;
char *sys_name;
struct string * disp_name;
int flags;
{
DPRINT(Debug,12,(&Debug,
"set_dir_selection: dir=%p; type=%p%s\n",
dir,dir->type,
dir->selection ? " (clearing previous selection)" : ""));
if (dir->selection)
clear_dir_selection(dir);
DPRINT(Debug,12,(&Debug,
"set_dir_selection: sys_name=%s, flags=%X",
sys_name ? sys_name : "<NULL>",flags));
if (disp_name) {
DPRINT(Debug,12,(&Debug,
", disp_name=%S\n",disp_name));
} else {
DPRINT(Debug,12,(&Debug,
", disp_name=NULL\n"));
}
dir->selection = safe_malloc(sizeof (struct name_vector));
/* bzero is defined hdrs/defs.h */
bzero((void *)dir->selection,sizeof (struct name_vector));
dir->selection->sys_name = sys_name;
dir->selection->disp_name = disp_name;
dir->selection->flags = flags;
}
void clear_dir_vector(dir)
struct folder_browser *dir;
{
int i;
DPRINT(Debug,12,(&Debug,
"clear_dir_vector: dir=%p; type=%p\n",
dir,dir->type));
if (dir->vector) {
if (dir->vector_len < 0) {
panic("BROWSER PANIC",__FILE__,__LINE__,"clear_dir_vector",
"Bad vector len (non-null vector)",0);
}
for (i = 0; i < dir->vector_len; i++) {
if (dir->vector[i].sys_name) {
free(dir->vector[i].sys_name);
dir->vector[i].sys_name = NULL;
}
if (dir->vector[i].disp_name)
free_string(&(dir->vector[i].disp_name));
}
free(dir->vector);
dir->vector = NULL;
dir->vector_len = 0;
} else {
if (dir->vector_len > 0) {
panic("BROWSER PANIC",__FILE__,__LINE__,"clear_dir_vector",
"Bad vector len (null vector)",0);
}
dir->vector_len = 0;
}
}
/* WARNING: add_dir_vector does not allocate strings --
* it just assign pointers!
*/
void add_dir_vector(dir, sys_name, disp_name, flags)
struct folder_browser *dir;
char *sys_name;
struct string * disp_name;
int flags;
{
DPRINT(Debug,12,(&Debug,
"add_dir_vector: dir=%p; type=%p\n",
dir,dir->type));
if (dir->vector_len < 0) {
DPRINT(Debug,12,(&Debug,
"add_dir_vector: RESETTING vector_len=%d to 0\n",
dir->vector_len));
if (dir->vector) {
panic("BROWSER PANIC",__FILE__,__LINE__,"add_dir_vector",
"Bad vector len (non-null vector)",0);
}
dir->vector_len = 0;
}
DPRINT(Debug,12,(&Debug,
"add_dir_vector: [%d].sys_name=%s, [%d].disp_name=%S, [%d].flags=%X%s\n",
dir->vector_len,sys_name,
dir->vector_len,disp_name,
dir->vector_len,flags,
flags & BROWSER_NEEDSTAT ? " (need stat)" : ""));
dir->vector = safe_realloc (dir->vector,
(dir->vector_len+1) * sizeof (dir->vector[0]));
dir->vector[dir->vector_len].sys_name = sys_name;
dir->vector[dir->vector_len].disp_name = disp_name;
dir->vector[dir->vector_len].flags = flags;
dir->vector[dir->vector_len].mtime = 0;
dir->vector_len++;
}
static void free_browser P_((struct folder_browser **dir));
static void free_browser(dir)
struct folder_browser **dir;
{
(*dir)->type->browser_free_it(*dir);
clear_dir_vector(*dir);
if ((*dir)->selection)
clear_dir_selection(*dir);
if ((*dir)->dirname)
free_string(&((*dir)->dirname));
if ((*dir)->filter)
free_string(&((*dir)->filter));
if ((*dir)->sys_dir) {
free((*dir)->sys_dir);
(*dir)->sys_dir = NULL;
}
free(*dir);
*dir = NULL;
}
void free_dir(dir)
struct folder_browser **dir;
{
if (!valid_browser((*dir)->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"free_dir",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"free_dir: *dir=%p (%s); type=%p\n",
*dir,(*dir)->sys_dir ? (*dir)->sys_dir : "<NULL>",
(*dir)->type));
free_browser(dir);
}
static struct folder_browser * browser_malloc2 P_((
enum selection_type sel_type,
struct browser_type *type
));
static struct folder_browser * browser_malloc2(sel_type,type)
enum selection_type sel_type;
struct browser_type *type;
{
struct folder_browser * dir = safe_malloc(sizeof (struct folder_browser));
bzero((void *)dir,sizeof (*dir)); /* defined hdrs/defs.h */
dir->sys_dir = NULL;
dir->dirname = NULL;
dir->filter = NULL;
dir->sel_type = sel_type;
dir->vector = NULL;
dir->vector_len = 0;
dir->selection = NULL;
dir->type = type;
dir->type->browser_zero_it(dir);
return dir;
}
static struct folder_browser * browser_malloc
P_((enum selection_type sel_type));
static struct folder_browser * browser_malloc(sel_type)
enum selection_type sel_type;
{
return browser_malloc2(sel_type,&dummy_browser);
}
#ifdef REMOTE_MBX
uint16 browser_URL_default_port(schema)
CONST struct browser_url_method *schema;
{
uint16 port;
if (BROWSER_URL_method_magic != schema->magic)
panic("BROWSER PANIC",__FILE__,__LINE__,"browser_URL_default_port",
"Bad schema magic",0);
port = schema->url_default_port_it(schema);
return port;
}
/* May not be
uin16 port
because this is promoted to int
*/
struct folder_browser * browser_connect_URL(schema,user,password,host,port)
CONST struct browser_url_method *schema;
CONST struct string *user /* May be NULL */;
CONST struct string *password /* May be NULL */;
CONST char *host /* May be NULL */;
int port /* May be NULL */;
{
struct folder_browser * dir;
struct connection_cache *con;
if (BROWSER_URL_method_magic != schema->magic)
panic("BROWSER PANIC",__FILE__,__LINE__,"browser_connect_URL",
"Bad schema magic",0);
con = schema->url_make_it(schema,user,password,host,port);
if (!con) {
DPRINT(Debug,10,(&Debug,
"browser_connect_URL=NULL: url_make_it failed \n"));
return NULL;
}
dir = browser_malloc2(selection_url,schema->type);
browser_from_connection(con,dir);
DPRINT(Debug,10,(&Debug,
"browser_connect_URL=%p\n",
dir));
return dir;
}
/* Returns 1 on succeed */
/* This is always absolute path -- from root as defined for URL */
int select_item_from_URL(schema,browser,elems_count,elems)
const struct browser_url_method *schema;
struct folder_browser *browser;
int elems_count;
const struct string **elems;
{
int ret;
if (BROWSER_URL_method_magic != schema->magic)
panic("BROWSER PANIC",__FILE__,__LINE__,
"select_item_from_URL_directory",
"Bad schema magic",0);
/* Force type to correct */
change_type(browser,schema->type);
ret = schema->url_select_item_from_it_URL(schema,browser,elems_count,elems);
return ret;
}
#endif
struct folder_browser *new_browser(sel_type)
enum selection_type sel_type;
{
struct folder_browser * dir;
DPRINT(Debug,10,(&Debug,
"new_browser: sel_type = %d\n",sel_type));
dir = browser_malloc(sel_type);
DPRINT(Debug,10,(&Debug,
"new_browser=%p type = %p\n",dir,dir->type));
return dir;
}
static int change_type(dir,new_type)
struct folder_browser *dir;
struct browser_type *new_type;
{
if (!valid_browser(new_type))
panic("BROWSER PANIC",__FILE__,__LINE__,"change_type",
"Bad new browser type",0);
if (new_type == dir->type)
return 0;
DPRINT(Debug,11,(&Debug,
"change_type: dir=%p Changing type from %p to %p\n",
dir,dir->type,new_type));
dir->type->browser_free_it(dir);
/* Assurance for clean start */
bzero((void *)&(dir->a), sizeof (dir->a));
dir->type = new_type;
dir->type->browser_zero_it(dir);
/* Be sure that caching request does not follow
when browser type changes...
*/
if (dir->vector_len < 0) {
DPRINT(Debug,12,(&Debug,
"change_type: RESETTING vector_len=%d to 0\n",
dir->vector_len));
if (dir->vector) {
panic("BROWSER PANIC",__FILE__,__LINE__,"change_type",
"Bad vector len (non-null vector)",0);
}
dir->vector_len = 0;
}
return 1;
}
/* NOTE:
'spec' given on tail_expander is assumed to be mailbox.
Therefore 'user@hostname' as IMAP mailbox is interpreted
as 'user@hostname:INBOX'
*/
static int tail_expander P_((struct folder_browser *dir,
struct string **buffer,
int pos, char *spec,
struct string **relative_to_type));
static int tail_expander(dir,buffer,pos,spec,relative_to_type)
struct folder_browser *dir;
struct string **buffer;
int pos;
char *spec;
struct string **relative_to_type;
{
int ret = 0;
int code = 0;
struct string * tempbuf = NULL;
#ifdef REMOTE_MBX
struct remote_account X;
struct service_entry *se = NULL;
char *rest = NULL;
DPRINT(Debug,15,(&Debug,
"tail_expander: Trying %s as remote address...\n",
spec));
/* 'spec' is some folder ... */
zero_remote_account(&X);
/* -1 == name not found or bad syntax
0 == not a remote address
1 == name found
*/
if (0 != (code = split_remote_name(spec,&X,&se,&rest,
0 /* Both POP and IMAP are OK */
))) {
if (code < 0) { /* ERROR */
free_temporary_service_entry(&se);
goto fail;
}
switch(dir->sel_type) {
case selection_file:
/* Use dummy browser to store information ... (not supported) */
DPRINT(Debug,15,(&Debug,
"tail_expander: user=%s host=%s -- remote unsupported file\n",
X.username,X.host));
if (change_type(dir,&dummy_browser))
clear_dir_vector(dir);
if (dir->a.dummy_browser.remote)
free(dir->a.dummy_browser.remote);
dir->a.dummy_browser.remote =
elm_message(FRM("%s@%s"),X.username,X.host);
free_remote_account(&X);
if (rest) {
switch(rest[0]) {
case ':':
tempbuf = new_string2(system_charset,
s2us(rest+1));
break;
case '/':
tempbuf = new_string2(system_charset,
s2us(rest));
break;
default:
panic("BROWSER PANIC",__FILE__,__LINE__,
"tail_expander",
"Bad return from split_remote_name",0);
}
} else
/* Empty directory assumed ... */
tempbuf = new_string2(system_charset,s2us(""));
break;
case selection_folder:
if (!rest && pos >= string_len(*buffer)) {
/* Can be either IMAP or POP mailbox, use
dummy browser to store information
*/
DPRINT(Debug,15,(&Debug,
"tail_expander: user=%s host=%s is either POP or IMAP\n",
X.username,X.host));
if (change_type(dir,&dummy_browser))
clear_dir_vector(dir);
if (dir->a.dummy_browser.remote)
free(dir->a.dummy_browser.remote);
dir->a.dummy_browser.remote =
elm_message(FRM("%s@%s"),X.username,X.host);
free_remote_account(&X);
*relative_to_type = NULL;
} else {
/* Other case it must be IMAP connection ... */
DPRINT(Debug,15,(&Debug,
"tail_expander: Trying user=%s host=%s as IMAP\n",
X.username,X.host));
if (dir->type == &imap_browser &&
dir->a.imap_browser.Ch &&
dir->a.imap_browser.Ch->C.username &&
dir->a.imap_browser.Ch->C.host &&
0 == strcmp(dir->a.imap_browser.Ch->C.username,
X.username) &&
0 == istrcmp(dir->a.imap_browser.Ch->C.host,
X.host)) {
DPRINT(Debug,15,(&Debug,
"tail_expander: already correct connection\n"));
} else {
static struct connection_cache *CX;
PORTS ports_imaponly[] = { PORT_imap4, PORT_end };
int got;
/* Only IMAP connections are cached */
CX = locate_from_cache(X.username,X.host,&IMAP_connection,
0 /* Default port */);
if (CX) {
if (change_type(dir,&imap_browser))
clear_dir_vector(dir);
browser_from_connection(CX,dir);
} else if (connect_remote_account(&X,&got,
se,ports_imaponly,
PORT_end)) {
if (change_type(dir,&imap_browser))
clear_dir_vector(dir);
if (!join_connection(dir->a.imap_browser.Ch,&X,
CON_greeting)) {
free_remote_account(&X);
goto fail;
}
} else {
free_remote_account(&X);
free_temporary_service_entry(&se);
goto fail;
}
}
/* Now we should have IMAP connection */
if (rest) {
switch(rest[0]) {
case ':':
tempbuf = new_string2(imap_charset,
s2us(rest+1));
break;
case '/':
tempbuf = new_string2(imap_charset,
s2us(rest));
break;
default:
panic("BROWSER PANIC",__FILE__,__LINE__,
"tail_expander",
"Bad return from split_remote_name",0);
}
} else
/* Sub directory of INBOX assumed */
tempbuf = new_string2(imap_charset,s2us("INBOX"));
}
}
}
free_remote_account(&X);
free_temporary_service_entry(&se);
#endif /* REMOTE_MBX */
if (0 == code) {
if (change_type(dir,
#if DIROPS
&local_browser
#else
&dummy_browser
#endif
))
clear_dir_vector(dir);
tempbuf = new_string2(local_fs_charset,s2us(spec));
}
if (pos < string_len(*buffer)) {
char sep;
int X = pos;
struct string *XX;
DPRINT(Debug,15,(&Debug,
"tail_expander: Changing directory for %s\n",
spec));
/* Change first directory specified on 'spec' */
if (!dir->type->browser_change_it(dir,tempbuf,&tempbuf))
goto fail;
sep = dir->type->browser_separator_it(dir);
if ('\0' == sep) {
struct string * msgname = dir->type->browser_name_it(dir);
lib_error(CATGETS(elm_msg_cat, MeSet, MeFlatError,
"%S have no subdirectories"),
msgname);
free_string(&msgname);
goto fail;
}
XX = clip_from_string(*buffer,&X,string_len(*buffer));
*relative_to_type =
format_string(FRM("%S%c%S"),tempbuf,sep,XX);
free_string(&XX);
} else { /* Directory given on 'spec' is current selection */
*relative_to_type = tempbuf;
tempbuf = NULL;
}
ret = 1;
fail:
if (tempbuf)
free_string(&tempbuf);
if (*relative_to_type) {
DPRINT(Debug,12,(&Debug,
"tail_expander: *relative_to_type=%S\n",
*relative_to_type));
} else {
DPRINT(Debug,12,(&Debug,
"tail_expander: *relative_to_type=NULL\n"));
}
DPRINT(Debug,12,(&Debug,
"tail_expander=%d\n",ret));
return ret;
}
static int expander P_((struct folder_browser *dir,
struct string **buffer,
struct string **relative_to_type));
static int expander(dir,buffer,relative_to_type)
struct folder_browser *dir;
struct string **buffer;
struct string **relative_to_type;
{
int ret = 0;
int len;
len = string_len(*buffer);
*relative_to_type = NULL;
if (len > 0) {
/* "." as last folder used,
"@alias" as default folder for user,
"=" as save by name and
"=?" as conditionally save by name
must be implemented on src/file.c or src/savecopy.c
others we can implement on here ...
These include:
"." as default directory
"~" as home directory of current user
"~user" as home directory of given user
"=" as folder directory
"+" as folder directory
"%" as folder directory
"!" as incoming mailbox
">" as received folder
"<" as sent folder
"$" as shell variable expansion (as local file)
"{rc}" as .elm directory (as local file)
"{lib}" as LIBHOME directory (as local file)
"{etc}" as ETCHOME directory (as local file)
"{doc}" as attachment-dir directory (as local file)
*/
uint16 code = give_unicode_from_string(*buffer,0);
DPRINT(Debug,15,(&Debug,"expander: First char %04X\n",code));
switch (code) {
int x, atpos,tailpos;
case 0x002E: /* '.' */
if (1 == len) { /* Default directory */
if (change_type(dir,
#if DIROPS
&local_browser
#else
&dummy_browser
#endif
))
clear_dir_vector(dir);
*relative_to_type = dup_string(*buffer);
ret = 1;
break;
}
goto other;
case 0x007E: /* '~' */
if (1 == len) { /* User's home directory */
if (change_type(dir,
#if DIROPS
&local_browser
#else
&dummy_browser
#endif
))
clear_dir_vector(dir);
*relative_to_type = new_string2(local_fs_charset,
s2us(home));
ret = 1;
break;
}
goto LOCAL_HANDLING;
case 0x003D: /* '=' */
case 0x002B: /* '+' */
case 0x0025: /* '%' */
/* Local folder directory */
if (1 == len) {
/* give_dt_estr_as_str adds / to end */
char * folders_val = give_dt_estr_as_str(&folders_e,"maildir");
if (!folders_val)
ret = 0;
else {
if (change_type(dir,
#ifdef DIROPS
&local_browser
#else
&dummy_browser
#endif
))
clear_dir_vector(dir);
*relative_to_type = new_string2(local_fs_charset,
s2us(folders_val));
ret = 1;
}
break;
}
goto LOCAL_HANDLING;
/* NOTE:
tail_expander assumes that 'spec' argument
(defaultfile, recvd_mail, sent_mail)
is mailbox. Therefore 'username@hostname'
is interpreted as 'username@hostname:INBOX'
for IMAP mailbox.
*/
case 0x0021: {
/* '!' incoming mailbox */
char * default_val = give_dt_estr_as_str(&defaultfile_e,"incoming-mailbox");
if (!default_val)
ret = 0;
else {
ret = tail_expander(dir,buffer,1,default_val,
relative_to_type);
if (ret && dir->sel_type == selection_file) {
if (*relative_to_type && 0 < string_len(*relative_to_type))
lib_error(CATGETS(elm_msg_cat, MeSet, MeUnsafeFile1,
"Name %S (expands to %s, %S) is unsafe use as file"),
*buffer, default_val, *relative_to_type);
else
lib_error(CATGETS(elm_msg_cat, MeSet, MeUnsafeFile2,
"Name %S (expands to %s) is unsafe use as file"),
*buffer, default_val);
ret = 0;
}
}
}
break;
case 0x003E: {
/* '>' received folder */
char * recvd_val = give_dt_estr_as_str(&recvd_mail_e,"receivedmail");
if (!recvd_val)
ret = 0 ;
else {
ret = tail_expander(dir,buffer,1,recvd_val,
relative_to_type);
if (ret && dir->sel_type == selection_file) {
if (*relative_to_type && 0 < string_len(*relative_to_type))
lib_error(CATGETS(elm_msg_cat, MeSet, MeUnsafeFile1,
"Name %S (expands to %s, %S) is unsafe use as file"),
*buffer, recvd_val, *relative_to_type);
else
lib_error(CATGETS(elm_msg_cat, MeSet, MeUnsafeFile2,
"Name %S (expands to %s) is unsafe use as file"),
*buffer, recvd_val);
ret = 0;
}
}
}
break;
case 0x003C: {
/* '<' sent folder */
char * sent_val = give_dt_estr_as_str(&sent_mail_e,"sentmail");
if (!sent_val)
ret = 0 ;
else {
ret = tail_expander(dir,buffer,1,sent_val,
relative_to_type);
if (ret && dir->sel_type == selection_file) {
if (*relative_to_type && 0 < string_len(*relative_to_type))
lib_error(CATGETS(elm_msg_cat, MeSet, MeUnsafeFile1,
"Name %S (expands to %s, %S) is unsafe use as file"),
*buffer, sent_val, *relative_to_type);
else
lib_error(CATGETS(elm_msg_cat, MeSet, MeUnsafeFile2,
"Name %S (expands to %s) is unsafe use as file"),
*buffer, sent_val);
ret = 0;
}
}
}
break;
default:
other:
/* Look if it starts with user@hostname */
atpos = -1;
tailpos = len;
for (x = 0; x < len; x++) {
uint16 code1 = give_unicode_from_string(*buffer,x);
if (0x0040 /* '@' */ == code1)
atpos = x;
else if (0x003A /* ':' */ == code1) {
tailpos = x+1;
break;
} else if (0x002F /* '/' */ == code1) {
tailpos = x;
break;
}
}
if (-1 != atpos) {
if (0 == atpos || atpos+1 == x) {
lib_error(CATGETS(elm_msg_cat, MeSet,MeBadRemoteMailbox1,
"Bad remote mailbox: %S"),
*buffer);
break;
}
if (x >= len) {
struct string * Lstr;
/* Can be either IMAP or POP mailbox, use
dummy browser to store information
*/
if (change_type(dir,&dummy_browser))
clear_dir_vector(dir);
if (dir->a.dummy_browser.remote)
free(dir->a.dummy_browser.remote);
Lstr = convert_string(system_charset,*buffer,0);
dir->a.dummy_browser.remote =
us2s(stream_from_string(Lstr,0,NULL));
free_string(&Lstr);
switch(dir->sel_type) {
case selection_file:
DPRINT(Debug,15,(&Debug,
"expander: %s is remote unsupported directory\n",
dir->a.dummy_browser.remote));
break;
case selection_folder:
DPRINT(Debug,15,(&Debug,
"expander: %s is either POP or IMAP\n",
dir->a.dummy_browser.remote));
break;
}
ret = 1;
} else {
#ifdef REMOTE_MBX
struct remote_account X;
struct service_entry *se = NULL;
char *rest = NULL; /* Ignored -- need NOT to be free'ed
* 'rest' is pointer to area of 'str'
*/
int ret_code;
struct string * Lstr =
convert_string(system_charset,*buffer,0);
unsigned char * str =
stream_from_string(Lstr,0,NULL);
/* Other case it must be IMAP connection ... */
zero_remote_account(&X);
DPRINT(Debug,15,(&Debug,
"expander: Trying %s as remote address...\n",
str));
/* -1 == name not found or bad syntax
0 == not a remote address
1 == name found
*/
if (0 <= (ret_code = split_remote_name(us2s(str),
&X,&se,&rest,
STFLAG_is_imap
/* Wanna IMAP */
))) {
if (ret_code == 0)
panic("BROWSER PANIC",__FILE__,__LINE__,"expander",
"Bad return from split_remote_name",0);
switch(dir->sel_type) {
case selection_file:
DPRINT(Debug,15,(&Debug,
"expander: user=%s host=%s -- remote unsupported file\n",
X.username,X.host));
break;
case selection_folder:
DPRINT(Debug,15,(&Debug,
"expander: Trying user=%s host=%s as IMAP\n",
X.username,X.host));
if (dir->type == &imap_browser &&
dir->a.imap_browser.Ch &&
dir->a.imap_browser.Ch->C.username &&
dir->a.imap_browser.Ch->C.host &&
0 == strcmp(dir->a.imap_browser.Ch->C.username,
X.username) &&
0 == istrcmp(dir->a.imap_browser.Ch->C.host,
X.host)) {
int X1 = tailpos;
DPRINT(Debug,15,(&Debug,
"expander: already correct connection\n"));
*relative_to_type =
clip_from_string(*buffer,&X1,len);
ret = 1;
} else {
static struct connection_cache *CX;
PORTS ports_imaponly[] = { PORT_imap4,
PORT_end };
int got;
/* Only IMAP connections are cached */
CX = locate_from_cache(X.username,X.host,
&IMAP_connection,
0 /* Default port */);
if (CX) {
int X1 = tailpos;
if (change_type(dir,&imap_browser))
clear_dir_vector(dir);
browser_from_connection(CX,dir);
ret = 1;
*relative_to_type =
clip_from_string(*buffer,&X1,len);
} else if (connect_remote_account(&X,&got,
se,
ports_imaponly,
PORT_end)) {
int X1 = tailpos;
if (change_type(dir,&imap_browser))
clear_dir_vector(dir);
ret = join_connection(dir->a.imap_browser.Ch,
&X,CON_greeting);
if (ret)
*relative_to_type =
clip_from_string(*buffer,&X1,len);
}
}
break;
}
}
free_string(&Lstr);
free(str);
free_remote_account(&X);
free_temporary_service_entry(&se);
#endif /* REMOTE_MBX */
if (!ret)
lib_error(CATGETS(elm_msg_cat, MeSet,
MeRemoteDirNotAvail1,
"Remote directries are not available in %.*S"),
x,*buffer);
}
} else {
char expand_space[LONG_STRING];
unsigned char * str;
struct string * Lstr;
/* Local mailbox handling */
DPRINT(Debug,15,(&Debug,
"expander: does not start with 'user@hostname' atpos=%d, scan ended = %d (len=%d)\n",atpos,x,len));
/* FALLTHRU */
case 0x0024: /* '$' shell variable expansion (as local file) */
case 0x007B: /* '{' {rc} as .elm directory (as local file)
* {lib} as LIBHOME directory (as local file)
* {etc} as ETCHOME directory (as local file)
* {doc} as attachment-dir (as local file)
*/
LOCAL_HANDLING: /* goto label ... */
Lstr = convert_string(local_fs_charset,*buffer,0);
str = stream_from_string(Lstr,0,NULL);
DPRINT(Debug,15,(&Debug,
"expander: Expanding %s (%S) as local\n",
str,Lstr));
if (expand_meta(expand_space,us2s(str),
sizeof expand_space) >= 0) {
if (change_type(dir,
#ifdef DIROPS
&local_browser
#else
&dummy_browser
#endif
))
clear_dir_vector(dir);
*relative_to_type = new_string2(local_fs_charset,
s2us(expand_space));
ret = 1;
}
free_string(&Lstr);
free(str);
}
break;
}
}
if (*relative_to_type) {
DPRINT(Debug,12,(&Debug,
"expander: *relative_to_type=%S\n",
*relative_to_type));
} else {
DPRINT(Debug,12,(&Debug,
"expander: *relative_to_type=NULL\n"));
}
DPRINT(Debug,12,(&Debug,"expander=%d\n",ret));
return ret;
}
/* Returns 1 if succesfully, and may canonify argument
may change type of dir
*/
int change_dir(dir,buffer)
struct folder_browser *dir;
struct string **buffer;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"change_dir",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"change_dir: dir=%p (%s); type=%p",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
if (*buffer) {
if (!verify_string(*buffer)) {
panic("BROWSER PANIC",__FILE__,__LINE__,"change_dir",
"Bad buffer (string)",0);
}
DPRINT(Debug,10,(&Debug,", *buffer=%S\n",*buffer));
} else {
DPRINT(Debug,10,(&Debug,", *buffer=NULL\n"));
}
if (dir->filter)
free_string(&(dir->filter));
if (*buffer &&
string_len(*buffer) > 0) {
struct string *relative_to_type = NULL;
if (expander(dir,buffer,&relative_to_type))
ret = dir->type->browser_change_it(dir,relative_to_type,buffer);
if (relative_to_type)
free_string(&relative_to_type);
} else {
if (change_type(dir,&dummy_browser))
clear_dir_vector(dir);
ret = dir->type->browser_change_it(dir,*buffer,buffer);
}
DPRINT(Debug,10,(&Debug,
"change_dir=%d; dir=%p (%s); type=%p",
ret,
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
if (*buffer) {
DPRINT(Debug,10,(&Debug,", *buffer=%S\n",*buffer));
} else {
DPRINT(Debug,10,(&Debug,", *buffer=NULL\n"));
}
return ret;
}
int change_dir_to_entry(dir,entry,buffer)
struct folder_browser *dir;
int entry;
struct string **buffer;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"change_dir_to_entry",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"change_dir_to_entry: dir=%p (%s); type=%p, entry=%d\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type,
entry));
if (*buffer) {
if (!verify_string(*buffer)) {
panic("BROWSER PANIC",__FILE__,__LINE__,"change_dir_to_entry",
"Bad buffer (string)",0);
}
DPRINT(Debug,10,(&Debug,
"change_dir_to_entry- *buffer=%p\n",*buffer));
} else {
DPRINT(Debug,10,(&Debug,
"change_dir_to_entry- *buffer=NULL\n"));
}
if (dir->filter)
free_string(&(dir->filter));
/* browser_vector_len() will update cache */
if (entry < 0 || entry >= browser_vector_len(dir)) {
DPRINT(Debug,10,(&Debug,
"change_dir_to_entry: entry (%d) not in range (0-%d)\n",
entry,dir->vector_len-1));
ret = 0;
} else if (dir->dirname) {
ret = dir->type->browser_change_v_it(dir,&(dir->vector[entry]),buffer);
} else {
/* SPECIAL HANDLING FOR DEFAULT DIRECTORY */
struct string *relative_to_type = NULL;
if (*buffer)
free_string(buffer);
*buffer = dup_string(dir->vector[entry].disp_name);
if (expander(dir,buffer,&relative_to_type))
ret = dir->type->browser_change_it(dir,relative_to_type,buffer);
if (relative_to_type)
free_string(&relative_to_type);
}
if (*buffer) {
DPRINT(Debug,10,(&Debug,
"change_dir_to_entry=%d; *buffer=%S\n",
ret,*buffer));
} else {
DPRINT(Debug,10,(&Debug,
"change_dir_to_entry=%d; *buffer=NULL\n",ret));
}
return ret;
}
extern int change_dir_up(dir,buffer)
struct folder_browser *dir;
struct string **buffer;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"change_dir_up",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"change_dir_up: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type
));
if (*buffer) {
if (!verify_string(*buffer)) {
panic("BROWSER PANIC",__FILE__,__LINE__,"change_dir_up",
"Bad buffer (string)",0);
}
DPRINT(Debug,10,(&Debug,
"change_dir_up- *buffer=%S\n",*buffer));
} else {
DPRINT(Debug,10,(&Debug,
"change_dir_up- *buffer=NULL\n"));
}
if (dir->filter)
free_string(&(dir->filter));
if (dir->dirname) {
/* Not possible to go up from default directory / menu */
ret = dir->type->browser_change_up_it(dir,buffer);
if (ret < 0) {
DPRINT(Debug,10,(&Debug,
"change_dir_up: Returning to default menu...\n"));
if (change_type(dir,
&dummy_browser
))
clear_dir_vector(dir);
browser_gen_default_menu(dir);
if (*buffer)
free_string(buffer);
ret = 1;
} else if (ret > 0) {
/* Do actual change ... */
ret = change_dir(dir,buffer);
}
}
if (*buffer) {
DPRINT(Debug,10,(&Debug,
"change_dir_up=%d; *buffer=%S\n",ret,*buffer));
} else {
DPRINT(Debug,10,(&Debug,
"change_dir_up=%d; *buffer=NULL\n",ret));
}
return ret;
}
struct string * give_title_dir(dir,entry_count)
struct folder_browser *dir;
int *entry_count;
{
struct string * ret;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"give_title_dir",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"give_title_dir: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
/* browser_vector_len() will update cache */
ret = dir->type->browser_give_title_it(dir);
*entry_count = browser_vector_len(dir);;
DPRINT(Debug,10,(&Debug,
"give_title_dir=%S *entry_count=%d\n",
ret,*entry_count));
return ret;
}
void folder_sort_dir(dir,print)
struct folder_browser *dir;
print_sort_message * print;
{
struct string * ret;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"folder_sort_dir",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"folder_sort_dir: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
/* browser_vector_len() will update cache */
browser_vector_len(dir);
dir->type->browser_folder_sort_it(dir,print);
}
/* return reference to array -- do not free_string() result !!! */
struct string * give_line_dir(dir,idx,flags)
struct folder_browser *dir;
int idx;
int *flags;
{
struct string * ret;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"give_line_dir",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"give_line_dir: dir=%p (%s); type=%p, idx=%d\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type,
idx));
/* browser_vector_len() will update cache */
if (idx < 0 || idx >= browser_vector_len(dir))
panic("BROWSER PANIC",__FILE__,__LINE__,"give_line_dir",
"Bad directory list index",0);
ret = dir->vector[idx].disp_name;
if (dir->vector[idx].flags & BROWSER_NEEDSTAT) {
DPRINT(Debug,10,(&Debug,
"give_line_dir: Updating flags -- doing stat\n"));
dir->type->browser_stat_routine(dir,idx);
}
*flags = dir->vector[idx].flags;
DPRINT(Debug,10,(&Debug,
"give_line_dir=%S; *flags=%X\n",ret,*flags));
return ret;
}
int select_dir_item(dir,buffer)
struct folder_browser *dir;
struct string **buffer;
{
int ret = 0;
int len;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"select_dir_item",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"select_dir_item: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
if (!verify_string(*buffer)) {
panic("BROWSER PANIC",__FILE__,__LINE__,"select_dir_item",
"Bad buffer (string)",0);
}
len = string_len(*buffer);
if (len > 0) {
struct string *relative_to_type = NULL;
if (expander(dir,buffer,&relative_to_type))
ret = dir->type->browser_select_it(dir,relative_to_type,buffer);
if (relative_to_type)
free_string(&relative_to_type);
} else {
if (change_type(dir,&dummy_browser))
clear_dir_vector(dir);
ret = dir->type->browser_select_it(dir,*buffer,buffer);
}
DPRINT(Debug,10,(&Debug,
"select_dir_item=%d; dir=%p (%s); type=%p, *buffer=%p\n",
ret,
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type,
*buffer));
return ret;
}
int give_edit_buffer(dir,entry,buffer,fill_with_entry)
struct folder_browser *dir;
int entry;
struct string **buffer;
int fill_with_entry;
{
int ret = 1;
struct string *res = NULL;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"give_edit_buffer",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"give_edit_buffer: dir=%p (%s); type=%p, entry=%d, (fill)=%d\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type,
entry,fill_with_entry));
if (*buffer) {
if (!verify_string(*buffer)) {
panic("BROWSER PANIC",__FILE__,__LINE__,"give_edit_buffer",
"Bad buffer (string)",0);
}
DPRINT(Debug,10,(&Debug,
"give_edit_buffer- *buffer=%p\n",*buffer));
} else {
DPRINT(Debug,10,(&Debug,
"give_edit_buffer- *buffer=NULL\n"));
}
/* NOTE: dir->sys_dir does not include possible user@host
* but dir->dirname includes possible user@host !
*
* dir->dirname is when default directory (menu) is selected
*
* browser_vector_len() will update cache
*/
if (entry < 0 ||
entry >= browser_vector_len(dir)) {
DPRINT(Debug,10,(&Debug,
"give_edit_buffer: entry (%d) not in range (0-%d)\n",
entry,dir->vector_len-1));
fill_with_entry = 0;
ret = 0;
}
if (fill_with_entry)
res = dir->type->browser_cat_it(dir,
dir->vector[entry].disp_name);
else
res = dir->type->browser_cat_it(dir,NULL);
if (res) {
if (*buffer)
free_string(buffer);
*buffer = res;
} else {
DPRINT(Debug,10,(&Debug,
"give_edit_buffer: failed -- NO CHANGE OF BUFFER!\n"));
ret = 0;
}
if (*buffer) {
DPRINT(Debug,10,(&Debug,
"give_edit_buffer=%d; *buffer=%S\n",ret,*buffer));
} else {
DPRINT(Debug,10,(&Debug,
"give_edit_buffer=%d; *buffer=NULL\n",ret));
}
return ret;
}
static void filter_director P_((struct folder_browser *dir));
static void filter_director(dir)
struct folder_browser *dir;
{
int i;
DPRINT(Debug,12,(&Debug,
"filter_director: dir=%p; type=%p\n",
dir,dir->type));
for (i = 0; i < dir->vector_len; i++) {
if (!string_match(dir->vector[i].disp_name,
dir->filter)) {
int j;
if (dir->vector[i].sys_name) {
free(dir->vector[i].sys_name);
dir->vector[i].sys_name = NULL;
}
if (dir->vector[i].disp_name)
free_string(&(dir->vector[i].disp_name));
for (j = i+1; j < dir->vector_len; j++) {
dir->vector[j-1] = dir->vector[j];
dir->vector[j].sys_name = NULL;
dir->vector[j].disp_name = NULL;
}
dir->vector_len--;
i--;
}
}
}
int dir_is_wildcard(dir,buffer)
struct folder_browser *dir;
struct string **buffer;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"dir_is_wildcard",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"dir_is_wildcard: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
if (dir->filter)
free_string(&(dir->filter));
if (*buffer) {
int len,x;
struct string *relative_to_type = NULL;
if (!verify_string(*buffer)) {
panic("BROWSER PANIC",__FILE__,__LINE__,"dir_is_wildcard",
"Bad buffer (string)",0);
}
DPRINT(Debug,10,(&Debug,
"dir_is_wildcard- *buffer=%p\n",*buffer));
len = string_len(*buffer);
for (x = 0; x < len; x++) {
uint16 code1 = give_unicode_from_string(*buffer,x);
if (0x002A /* '*' */ == code1) {
ret = 1;
break;
} else if (0x003F /* '?' */ == code1) {
ret = 1;
break;
}
}
if (!ret) {
DPRINT(Debug,10,(&Debug,
"dir_is_wildcard: No wildcards\n"));
goto fail;
}
if (expander(dir,buffer,&relative_to_type)) {
int base_len = 0;
int sep = dir->type->browser_separator_it(dir);
int X = 0;
struct string * new_relative = NULL;
struct string * dispname = NULL;
int disp_len = 0;
int X2 = 0;
int len1 = 0;
if (relative_to_type) {
int x1;
len1 = string_len(relative_to_type);
for (x1 = 0; x1 < len1; x1++) {
uint16 code1 =
give_unicode_from_string(relative_to_type,x1);
if (0x002A /* '*' */ == code1) {
break;
} else if (0x003F /* '?' */ == code1) {
break;
} else if (sep && sep == code1) {
/* (separator) character set is assumed to be
ASCII compatible on here! */
base_len = x1+1;
}
}
if (0 == base_len &&
(dir->type == &dummy_browser
#if DIROPS
|| dir->type == &local_browser
#endif
)) {
/* Special case:
Treat adas*hjghj as filtering of current
directory (and not filtering of default menu)
*/
new_relative = new_string2(system_charset,s2us("."));
dispname = new_string2(system_charset,s2us("."));
if (change_type(dir,
#if DIROPS
&local_browser
#else
&dummy_browser
#endif
))
clear_dir_vector(dir);
} else {
for (x = 0; x < len; x++) {
uint16 code1 = give_unicode_from_string(*buffer,x);
if (0x002A /* '*' */ == code1) {
break;
} else if (0x003F /* '?' */ == code1) {
break;
} else if (sep && sep == code1) {
/* (separator) character set is assumed to be
ASCII compatible on here! */
disp_len = x+1;
}
}
new_relative = clip_from_string(relative_to_type,&X,
base_len);
if (0 == disp_len) {
/* HACK for =* */
dispname = dup_string(new_relative);
} else
dispname = clip_from_string(*buffer,&X2,disp_len);
}
} else {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadWildcard,
"Bad wildcard specification %S"),
*buffer);
/* new_relative == NULL, but that is OK */
dispname = dup_string(*buffer);
}
if (dir->type->browser_change_it(dir,new_relative,&dispname)) {
dir->filter = clip_from_string(relative_to_type,&X,len1);
if (dir->vector_len >= 0)
filter_director(dir);
}
if (new_relative)
free_string(&new_relative);
free_string(&dispname);
}
if (relative_to_type)
free_string(&relative_to_type);
} else {
DPRINT(Debug,10,(&Debug,
"dir_is_wildcard- *buffer=NULL\n"));
}
fail:
if (*buffer) {
DPRINT(Debug,10,(&Debug,
"dir_is_wildcard=%d; *buffer=%S\n",ret,*buffer));
} else {
DPRINT(Debug,10,(&Debug,
"dir_is_wildcard=%d; *buffer=NULL\n",ret));
}
return ret;
}
struct folder_info * folder_from_dir_item(dir)
struct folder_browser *dir;
{
struct folder_info * res = NULL;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"folder_from_dir_item",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"folder_from_dir_item: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
if (!dir->selection)
panic("BROWSER PANIC",__FILE__,__LINE__,"folder_from_dir_item",
"No selection",0);
res = dir->type->browser_folder_from_it(dir);
if (res) {
DPRINT(Debug,10,(&Debug,
"folder_from_dir_item=%p (%s), type=%p\n",
res,res->cur_folder_sys,res->folder_type));
} else {
DPRINT(Debug,10,(&Debug,"folder_from_dir_item=NULL\n"));
}
return res;
}
int give_dir_flags(dir)
struct folder_browser *dir;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"give_dir_flags",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"folder_dir_flags: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
if (dir->selection)
ret |= BROWSER_SELECTED | dir->selection->flags;
DPRINT(Debug,10,(&Debug, "folder_dir_flags=%X\n",ret));
return ret;
}
int create_selection_dir(dir)
struct folder_browser *dir;
{
int res = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"create_selection_dir",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"create_selection_dir: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
if (!dir->selection)
panic("BROWSER PANIC",__FILE__,__LINE__,"create_selection_dir",
"No selection",0);
res = dir->type->browser_create_selection_it(dir);
DPRINT(Debug,10,(&Debug,"create_selection_dir=%d\n",res));
return res;
}
static void malloc_keep_browser_write_state P_((WRITE_STATE * ptr));
static void malloc_keep_browser_write_state(ptr)
WRITE_STATE * ptr;
{
(*ptr) = safe_malloc(sizeof (struct browser_write_state));
/* bzero is defined hdrs/defs.h */
bzero((void *)*ptr,sizeof (struct browser_write_state));
(*ptr)->magic = WS_magic;
}
static void free_keep_browser_write_state P_((WRITE_STATE * ptr));
static void free_keep_browser_write_state(ptr)
WRITE_STATE * ptr;
{
if (*ptr) {
/* bzero is defined hdrs/defs.h */
bzero((void *)*ptr,sizeof (struct browser_write_state));
free(*ptr);
*ptr = NULL;
}
}
int prepare_write_folder(dir,write_state_ptr)
struct folder_browser *dir;
WRITE_STATE * write_state_ptr;
{
int ret = 0;
WRITE_STATE ptr = NULL;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"prepare_write_folder",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"prepare_write_folder: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
if (!dir->selection)
panic("BROWSER PANIC",__FILE__,__LINE__,"prepare_write_folder",
"No selection",0);
malloc_keep_browser_write_state(&ptr);
dir->type->zero_ws_fields_it(ptr);
ret = dir->type->browser_prepare_write_it(dir,ptr);
if (!ret) {
dir->type->free_ws_fields_it(ptr);
free_keep_browser_write_state(&ptr);
}
*write_state_ptr = ptr;
DPRINT(Debug,10,(&Debug,"prepare_write_folder=%d\n",ret));
return ret;
}
int sync_write_folder(dir,write_state_ptr)
struct folder_browser *dir;
WRITE_STATE write_state_ptr;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"sync_write_folder",
"Bad browser (type)",0);
if (write_state_ptr->magic != WS_magic)
panic("BROWSER PANIC",__FILE__,__LINE__,"sync_write_folder",
"Bad magic",0);
DPRINT(Debug,10,(&Debug,
"sync_write_folder: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
ret = dir->type->browser_sync_write_it(dir,write_state_ptr);
DPRINT(Debug,10,(&Debug,"sync_write_folder=%d\n",ret));
return ret;
}
int end_write_folder(dir,write_state_ptr)
struct folder_browser *dir;
WRITE_STATE * write_state_ptr;
{
int ret = 0;
WRITE_STATE ptr = *write_state_ptr;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"end_write_folder",
"Bad browser (type)",0);
if (ptr->magic != WS_magic)
panic("BROWSER PANIC",__FILE__,__LINE__,"end_write_folder",
"Bad magic",0);
DPRINT(Debug,10,(&Debug,
"end_write_folder: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
ret = dir->type->browser_end_write_it(dir,ptr);
dir->type->free_ws_fields_it(ptr);
free_keep_browser_write_state(&ptr);
*write_state_ptr = ptr;
DPRINT(Debug,10,(&Debug,"end_write_folder=%d\n",ret));
return ret;
}
struct string * selection_name_dir(dir)
struct folder_browser *dir;
{
struct string * ret = NULL;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"selection_name_dir",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"selection_name_dir: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
if (!dir->selection)
panic("BROWSER PANIC",__FILE__,__LINE__,"selection_name_dir",
"No selection",0);
ret = dir->type->browser_cat_it(dir,dir->selection->disp_name);
if (ret) {
DPRINT(Debug,10,(&Debug,
"selection_name_dir=%S\n",ret));
} else {
DPRINT(Debug,10,(&Debug,
"selection_name_dir=NULL\n"));
}
return ret;
}
void clear_selection_dir(dir)
struct folder_browser *dir;
{
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"clear_selection_dir",
"Bad browser (type)",0);
DPRINT(Debug,10,(&Debug,
"clear_selection_dir: dir=%p (%s); type=%p\n",
dir,dir->sys_dir ? dir->sys_dir : "<NULL>",
dir->type));
clear_dir_selection(dir);
}
/* helper routines for fileio.c */
void start_fd_write_state(fd,dir,write_state_ptr)
FILE *fd;
struct folder_browser **dir;
WRITE_STATE *write_state_ptr;
{
WRITE_STATE ptr = NULL;
DPRINT(Debug,10,(&Debug,"start_fd_write_state: fd=%p\n",fd));
*dir = browser_malloc(selection_folder);
malloc_keep_browser_write_state(&ptr);
(*dir)->type->zero_ws_fields_it(ptr);
ptr->a.local.save_file = fd; /* WARNING: shared pointer! */
*write_state_ptr = ptr;
DPRINT(Debug,10,(&Debug,
"start_fd_write_state: *dir=%p; type=%p\n",
*dir,(*dir)->type));
}
void end_fd_write_state(dir,write_state_ptr)
struct folder_browser **dir;
WRITE_STATE *write_state_ptr;
{
WRITE_STATE ptr = *write_state_ptr;
if (!valid_browser((*dir)->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"end_fd_write_state",
"Bad browser (type)",0);
if (ptr->magic != WS_magic)
panic("BROWSER PANIC",__FILE__,__LINE__,"end_fd_write_state",
"Bad magic",0);
DPRINT(Debug,10,(&Debug,
"end_fd_write_state: *dir=%p; type=%p\n",
*dir,(*dir)->type));
ptr->a.local.save_file = NULL; /* Reset shared pointer! */
(*dir)->type->free_ws_fields_it(ptr);
free_keep_browser_write_state(&ptr);
*write_state_ptr = ptr;
free_browser(dir);
}
/* Returns -1 if not seekable, else position */
long tell_dir_write_state(dir,write_state_ptr)
struct folder_browser *dir;
WRITE_STATE write_state_ptr;
{
long ret = -1;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"tell_dir_write_state",
"Bad browser (type)",0);
if (write_state_ptr->magic != WS_magic)
panic("BROWSER PANIC",__FILE__,__LINE__,"tell_dir_write_state",
"Bad magic",0);
DPRINT(Debug,10,(&Debug,
"tell_dir_write_state: *dir=%p; type=%p\n",
dir,dir->type));
ret = dir->type->browser_tell_it_ws(dir,write_state_ptr);
DPRINT(Debug,10,(&Debug,"tell_dir_write_state=%ld\n",ret));
return ret;
}
/* Returns 0 on failure! */
int seek_dir_write_state(dir,write_state_ptr,pos)
struct folder_browser *dir;
WRITE_STATE write_state_ptr;
long pos;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"seek_dir_write_state",
"Bad browser (type)",0);
if (write_state_ptr->magic != WS_magic)
panic("BROWSER PANIC",__FILE__,__LINE__,"seek_dir_write_state",
"Bad magic",0);
DPRINT(Debug,10,(&Debug,
"seek_dir_write_state: *dir=%p; type=%p, pos=%ld\n",
dir,dir->type,pos));
ret = dir->type->browser_seek_it_ws(dir,write_state_ptr,pos);
DPRINT(Debug,10,(&Debug,"seek_dir_write_state=%d\n",ret));
return ret;
}
/* Return 0 on failure */
int write_dir_write_state(dir,write_state_ptr,l,buffer)
struct folder_browser *dir;
WRITE_STATE write_state_ptr;
int l;
CONST char *buffer;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"write_dir_write_state",
"Bad browser (type)",0);
if (write_state_ptr->magic != WS_magic)
panic("BROWSER PANIC",__FILE__,__LINE__,"write_dir_write_state",
"Bad magic",0);
DPRINT(Debug,10,(&Debug,
"write_dir_write_state: *dir=%p; type=%p, len=%d\n",
dir,dir->type,l));
ret = dir->type->browser_write_it_ws(dir,write_state_ptr,l,buffer);
DPRINT(Debug,10,(&Debug,"write_dir_write_state=%d\n",ret));
return ret;
}
int write_envelope_start(dir,write_state_ptr,write_envelope,current_header,
env_flags)
struct folder_browser *dir;
WRITE_STATE write_state_ptr;
int write_envelope;
struct header_rec *current_header;
int *env_flags;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"write_envelope_start",
"Bad browser (type)",0);
if (write_state_ptr->magic != WS_magic)
panic("BROWSER PANIC",__FILE__,__LINE__,"write_envelope_start",
"Bad magic",0);
DPRINT(Debug,10,(&Debug,
"write_write_envelope_start: *dir=%p; type=%p, write_envelope=%d\n",
dir,dir->type,write_envelope));
ret = dir->type->browser_start_we_it(dir,write_state_ptr,
write_envelope,current_header,
env_flags);
DPRINT(Debug,10,(&Debug,
"write_write_envelope_start=%d *env_flags=%d%s\n",
ret,*env_flags,
(*env_flags & WE_ADD_RETURN_PATH) ?
" WE_ADD_RETURN_PATH" : ""));
return ret;
}
int write_envelope_end(dir,write_state_ptr,write_envelope,current_header)
struct folder_browser *dir;
WRITE_STATE write_state_ptr;
int write_envelope;
struct header_rec *current_header;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"write_envelope_end",
"Bad browser (type)",0);
if (write_state_ptr->magic != WS_magic)
panic("BROWSER PANIC",__FILE__,__LINE__,"write_envelope_end",
"Bad magic",0);
DPRINT(Debug,10,(&Debug,
"write_write_envelope_end: *dir=%p; type=%p, write_envelope=%d\n",
dir,dir->type,write_envelope));
ret = dir->type->browser_end_we_it(dir,write_state_ptr,
write_envelope,current_header);
DPRINT(Debug,10,(&Debug,"write_write_envelope_end=%d\n",ret));
return ret;
}
int selection_is_folder(dir,folder)
struct folder_browser *dir;
struct folder_info *folder;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"selection_is_folder",
"Bad browser (type)",0);
if (!dir->selection)
panic("BROWSER PANIC",__FILE__,__LINE__,"selection_is_folder",
"No selection",0);
DPRINT(Debug,10,(&Debug,
"selection_is_folder: *dir=%p; type=%p, folder=%p\n",
dir,dir->type,folder));
ret = dir->type->browser_selection_is_it(dir,folder);
DPRINT(Debug,10,(&Debug,"selection_is_folder=%d\n",ret));
return ret;
}
int dir_make_ref(dir,refname,iscopy,is_text)
struct folder_browser *dir;
char **refname;
int *iscopy;
int is_text;
{
int ret = 0;
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"dir_make_ref",
"Bad browser (type)",0);
if (!dir->selection)
panic("BROWSER PANIC",__FILE__,__LINE__,"dir_make_ref",
"No selection",0);
DPRINT(Debug,10,(&Debug,
"dir_make_ref: *dir=%p; type=%p, is_text=%d\n",
dir,dir->type,is_text));
*refname = NULL;
*iscopy = 0;
ret = dir->type->browser_make_ref_it(dir,refname,iscopy,is_text);
DPRINT(Debug,10,(&Debug,"dir_make_ref=%d; *refname=%s, *iscopy=%d\n",
ret,
*refname ? *refname : "<NULL>",
*iscopy));
return ret;
}
int browser_vector_len(dir)
struct folder_browser *dir;
{
if (!valid_browser(dir->type))
panic("BROWSER PANIC",__FILE__,__LINE__,"browser_vector_len",
"Bad browser (type)",0);
if (dir->vector_len >= 0) {
DPRINT(Debug,12,(&Debug,
"browser_vector_len=%d, dir=%p\n",
dir->vector_len,dir));
return dir->vector_len;
}
DPRINT(Debug,12,(&Debug,
"browser_vector_len: dir=%p (updating cache)\n",
dir));
dir->type->browser_update_it(dir);
if (dir->filter)
filter_director(dir);
DPRINT(Debug,12,(&Debug,
"browser_vector_len=%d\n",
dir->vector_len));
return dir->vector_len;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1