static char rcsid[] = "@(#)$Id: remote_mbx.c,v 1.58 2006/07/01 07:37:48 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.58 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
*****************************************************************************/
#include "headers.h"
#include "ss_imp.h"
#include "connection_imp.h"
#ifdef USE_DLOPEN
#include "shared_imp.h"
#endif
#include "s_me.h"
#include "s_elm.h"
DEBUG_VAR(Debug,__FILE__,"net");
#ifdef POLL_METHOD
void zero_Read_Buffer(buffer)
struct Read_Buffer *buffer;
{
buffer->read_buffer = NULL;
buffer->read_len = 0;
}
void free_Read_Buffer(buffer)
struct Read_Buffer *buffer;
{
if (buffer->read_buffer) {
free(buffer->read_buffer);
buffer->read_buffer = NULL;
}
buffer->read_len = 0;
}
/* For non-lieral we read with quite short block because
many answers are quite small
*/
#define READ_BLOCK 1024
int ReadFromSocket(fd,buffer,wanted)
int fd;
struct Read_Buffer *buffer;
int wanted;
{
int n;
if (wanted > 0) {
buffer -> read_buffer = safe_realloc(buffer -> read_buffer,
buffer -> read_len + wanted);
n = read(fd, buffer -> read_buffer + buffer -> read_len, wanted);
} else {
buffer -> read_buffer = safe_realloc(buffer -> read_buffer,
buffer -> read_len + READ_BLOCK);
n = read(fd, buffer -> read_buffer + buffer -> read_len, READ_BLOCK);
}
return n;
}
int find_crlf(buffer, add_null)
struct Read_Buffer *buffer;
int add_null;
{
char * p = buffer->read_buffer;
int i;
for (i = 0; i < buffer->read_len -1; i++)
if ('\r' == p[i] && '\n' == p[i+1]) {
if (add_null) {
p[i] = '\0';
p[i+1] = '\0';
}
DPRINT(Debug,49,(&Debug,
"find_crlf=%d (%d total)\n",
i+2,buffer->read_len));
return i+2;
}
DPRINT(Debug,49,(&Debug,
"find_crlf=0 (%d total)\n",
buffer->read_len));
return 0;
}
void cut_line(buffer, len)
struct Read_Buffer *buffer;
int len;
{
char * p = buffer->read_buffer;
buffer->read_len -= len;
DPRINT(Debug,49,(&Debug,
"cut_line: %d chars consumed, %d left\n",
len,buffer->read_len));
if (buffer->read_len)
memmove(p, p+len, buffer->read_len);
}
void zero_Write_Buffer(buffer)
struct Write_Buffer *buffer;
{
buffer->write_buffer = NULL;
buffer->write_len = 0;
}
void free_Write_Buffer(buffer)
struct Write_Buffer *buffer;
{
if (buffer->write_buffer) {
free(buffer->write_buffer);
buffer->write_buffer = NULL;
}
buffer->write_len = 0;
}
int WriteToSocket(fd,buffer)
int fd;
struct Write_Buffer *buffer;
{
int n = write(fd,buffer->write_buffer, buffer->write_len);
return n;
}
void cut_Write_Buffer(buffer,n)
struct Write_Buffer *buffer;
int n;
{
if (n > 0) {
char * p = buffer->write_buffer;
buffer->write_len -= n;
if (buffer->write_len)
memmove(p, p+n, buffer->write_len);
DPRINT(Debug,13,(&Debug,
"cut_Write_Buffer: Written %d bytes (%d left)\n",
n,buffer->write_len));
}
}
void add_to_Write_Buffer(buffer,str,l)
struct Write_Buffer *buffer;
char **str;
int l;
{
if (!buffer->write_len) {
if (buffer->write_buffer)
free(buffer->write_buffer);
buffer->write_buffer = *str;
buffer->write_len = l;
} else if (l > 0) {
buffer->write_buffer = safe_realloc(buffer->write_buffer,
buffer->write_len+l);
memmove(buffer->write_buffer + buffer->write_len,*str,l);
buffer->write_len += l;
free(*str);
}
*str = NULL;
}
#endif
/* Seems that h_errno is macro on AIX */
#ifndef h_errno
extern int h_errno;
#endif
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
/* Closed only implicity on exit */
FILE * transaction_file = NULL;
int set_transaction_file(filename)
CONST char *filename;
{
FILE * f;
int err;
int fd;
if (userid == -1 || groupid == -1) {
/* save original user and group ids */
userid = getuid();
groupid = getgid();
DPRINT(Debug,1,(&Debug,"set_transaction_file: %s: Saving userid/groupid=%d/%d\n",
filename,userid,groupid));
}
err = can_open(filename,"a");
if (0 != err) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
"File %.50s is not writeable: %s"),
filename, error_description(err));
return 0;
}
fd = open(filename,O_CREAT|O_WRONLY|O_APPEND,00600);
if (-1 == fd) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
"File %.50s is not writeable: %s"),
filename, error_description(err));
return 0;
}
elm_chown(filename, userid, groupid); /* file owned by user */
f = fdopen(fd,"a");
if (!f) {
close(fd);
return 0;
}
if (transaction_file) {
fprintf(transaction_file,
"\n===== Changing logging to file %s\n",
filename);
fclose(transaction_file);
}
transaction_file = f;
#ifdef SETLINEBUF
setlinebuf(transaction_file);
#endif
DPRINT(Debug,1,(&Debug,
"set_transaction_file: %s: transaction file opened\n",
filename));
return 1;
}
#ifdef REMOTE_MBX
void zero_remote_account(ra)
struct remote_account *ra;
{
/* bzero is defined hdrs/defs.h */
bzero ((void *)ra, sizeof (struct remote_account));
ra->magic = REMOTE_ACCOUNT_magic;
ra->hostaddr.sa.sa_family = AF_UNSPEC;
ra->service_idx = 0;
ra->stream = NULL;
ra->username = NULL;
ra->host = NULL;
}
void free_remote_account(ra)
struct remote_account *ra;
{
if (ra->magic != REMOTE_ACCOUNT_magic)
panic("CONNECTION PANIC",__FILE__,__LINE__,
"free_remote_account",
"Bad magic number",0);
ra->hostaddr.sa.sa_family = AF_UNSPEC;
ra->service_idx = -1;
if (ra->stream)
FreeStreamStack(& (ra->stream));
if (ra->username) {
free(ra->username);
ra->username = NULL;
}
if (ra->host) {
free(ra->host);
ra->host = NULL;
}
}
#ifdef I_NETINET_IN
static int connect_one_IN P_((struct remote_account *ra,
int *cur_socket, int *last_error,
struct chancel_data *can));
static int connect_one_IN(ra,cur_socket,last_error,can)
struct remote_account *ra;
int *cur_socket;
int *last_error;
struct chancel_data *can;
{
int r = 0;
/* r == 0: not succeed
r < 0: fatal error
r > 0: succeed
*/
DPRINT(Debug,12,(&Debug,
"connect_one_IN: addr=%s, port=%d\n",
inet_ntoa(ra->hostaddr.sin.sin_addr),
ntohs(ra->hostaddr.sin.sin_port)));
#ifdef NEED_REOPEN_AFTER_FAILED_CONNECT
if (-1 != (*cur_socket)) {
DPRINT(Debug,12,(&Debug,
"connect_one_IN: NEED_REOPEN_AFTER_FAILED_CONNECT -- closing socket (%d) for reopening\n",
(*cur_socket)));;
close(*cur_socket);
(*cur_socket) = -1;
}
#endif
if (-1 == (*cur_socket)) {
(*cur_socket) = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if (-1 == (*cur_socket)) {
int err =errno;
lib_error(CATGETS(elm_msg_cat, MeSet,MeFailedToCreate,
"Failed to create socket: %s"),
error_description(err));
r = -1;
goto clean;
}
DPRINT(Debug,12,(&Debug,
"connect_one_IN: socket=%d\n",(*cur_socket)));
}
retry:
if (-1 == connect((*cur_socket),& (ra->hostaddr.sa),
sizeof (ra->hostaddr.sin))) {
(*last_error) = errno;
DPRINT(Debug,12,(&Debug,
"connect_one_IN: connect failed: %s\n",
error_description(*last_error)));
if (errno == EINVAL) {
/* Seems that it is not not allowed several connect
* attempts with same socket ...
*/
(*last_error) = errno;
DPRINT(Debug,12,(&Debug,
"connect_one_IN: -- reopening socket and retrying...\n"));
close(*cur_socket);
(*cur_socket) = socket(PF_INET,SOCK_STREAM,
IPPROTO_TCP);
if (-1 != (*cur_socket)) {
DPRINT(Debug,12,(&Debug,
"connect_one_IN: socket=%d\n",(*cur_socket)));
}
if (-1 == (*cur_socket) ||
-1 == connect(*cur_socket,&(ra->hostaddr.sa),
sizeof (ra->hostaddr.sin))) {
(*last_error) = errno;
DPRINT(Debug,12,(&Debug,
"connect_one_IN: connect failed: %s\n",
error_description(*last_error)));
} else
r = 1;
}
if (0 == r && EINTR == errno) {
if (is_canceled(can)) {
DPRINT(Debug,12,(&Debug,"connect canceled...\n"));
r = -1;
} else {
DPRINT(Debug,12,(&Debug,"Retrying connect...\n"));
goto retry;
}
}
} else
r = 1;
/* If got connection to host and and it refused
connection, try another ports
*/
if (r < 1 && *last_error != ECONNREFUSED)
r = -2;
clean:
DPRINT(Debug,12,(&Debug,
"connect_one_IN=%d%s\n",r,r > 0 ? " (succeed)" : ""));
return r;
}
#endif
int connect_remote_account(ra,got,se,default_portlist,force_port)
struct remote_account *ra;
int *got;
struct service_entry *se;
PORTS default_portlist[];
PORTS force_port;
{
int ok = 0;
int last_error = 0;
int cur_socket = -1;
int prev_family = AF_UNSPEC;
int was_canceled = 0;
int idx;
if (ra->magic != REMOTE_ACCOUNT_magic)
panic("CONNECTION PANIC",__FILE__,__LINE__,
"connect_remote_account",
"Bad magic number",0);
if(ra->stream) {
DPRINT(Debug,12,(&Debug,
"connect_remote_account: Closing for reopening\n"));
FreeStreamStack(& (ra->stream));
}
for (idx = 0; idx < se->addr_count; idx++) {
/* Copy all information */
ra->hostaddr = se->addr_list[idx];;
if (prev_family != ra->hostaddr.sa.sa_family &&
cur_socket != -1) {
DPRINT(Debug,12,(&Debug,
"connect_remote_account: family change from %d to %d -- closing socket (%d)\n",
prev_family,ra->hostaddr.sa.sa_family,
cur_socket
));
close(cur_socket);
cur_socket = -1;
}
switch (ra->hostaddr.sa.sa_family) {
int r;
#ifdef I_NETINET_IN
case AF_INET: {
struct chancel_data * can;
if (force_port != PORT_end)
can = new_cancel(CATGETS(elm_msg_cat, MeSet,MeConnectingPort,
"Connecting to %s [%s], port %d ... (%d)"),
se->official_name,
inet_ntoa(ra->hostaddr.sin.sin_addr),
force_port,
idx);
else
can = new_cancel(CATGETS(elm_msg_cat, MeSet,MeConnecting,
"Connecting to %s [%s]... (%d)"),
se->official_name,
inet_ntoa(ra->hostaddr.sin.sin_addr),
idx);
/* r == 0: not succeed
r < 0: fatal error
r > 0: succeed
*/
r = 0;
if (force_port != PORT_end) {
DPRINT(Debug,11,(&Debug,
"-- force_port = %d\n", force_port));
ra->hostaddr.sin.sin_port = htons(force_port);
r = connect_one_IN(ra,&cur_socket,&last_error,can);
if (r > 0)
*got = force_port;
} else if (ra->hostaddr.sin.sin_port != htons(PORT_end)) {
DPRINT(Debug,11,(&Debug,"-- address record gives port %d\n",
ntohs(ra->hostaddr.sin.sin_port)));
r = connect_one_IN(ra,&cur_socket,&last_error,can);
if (r > 0)
*got = ntohs(ra->hostaddr.sin.sin_port);
} else if (se->port_count > 0) {
int idx2;
DPRINT(Debug,11,(&Debug,
"-- service list gives portlist (%d ports)\n",
se->port_count));
for (idx2 = 0; idx2 < se->port_count && 0 == r; idx2++) {
ra->hostaddr.sin.sin_port =
htons(se->port_list[idx2]);
r = connect_one_IN(ra,&cur_socket,&last_error,can);
if (r > 0)
*got = se->port_list[idx2];
}
} else {
int idx2;
DPRINT(Debug,11,(&Debug,
"-- service list does not give portlist -- trying default portlist\n"));
for (idx2 = 0; default_portlist[idx2] != PORT_end && 0 == r;
idx2++) {
ra->hostaddr.sin.sin_port =
htons(default_portlist[idx2]);
r = connect_one_IN(ra,&cur_socket,&last_error,can);
if (r > 0)
*got = default_portlist[idx2];
}
}
if (r > 0) {
DPRINT(Debug,12,(&Debug,
"connect_remote_account: Connection succeed %s [%s], port %d\n",
se->official_name,
inet_ntoa(ra->hostaddr.sin.sin_addr),
*got));
ok = 1;
if (transaction_file) {
time_t tmp = time(NULL);
struct tm * zz = localtime(&tmp);
fprintf(transaction_file,
"%d [%d] %02d:%02d:%02d === CONNECT %s [%s], port %d\n",
getpid(),cur_socket,
zz ? zz->tm_hour : 00,
zz ? zz->tm_min : 00,
zz ? zz->tm_sec : 00,
se->official_name,
inet_ntoa(ra->hostaddr.sin.sin_addr),
*got);
}
}
was_canceled = is_canceled(can);
free_cancel(&can);
}
break;
#endif
default:
lib_error(CATGETS(elm_msg_cat, MeSet,MeUnsupportedAddrType,
"Name %s have odd type address"),
se->official_name);
break;
}
if (ok) {
DPRINT(Debug,20,(&Debug,
"connect_remote_account: Connection succeed -- quiting loop\n"));
break;
}
}
if (!ok) {
if (cur_socket != -1) {
DPRINT(Debug,12,(&Debug,
"connect_remote_account: Closing socket (%d) after failure\n",
cur_socket));
close(cur_socket);
cur_socket = -1;
}
if (was_canceled)
lib_error(CATGETS(elm_msg_cat, MeSet,MeConnectCanceled,
"Connect %s canceled."),
se->official_name);
else
lib_error(CATGETS(elm_msg_cat, MeSet,MeConnectFailed,
"Failed to connect %s: %s"),
se->official_name,error_description(last_error));
ok = 0;
goto clean;
}
/* We set folder to non-blocking after connect, because
* non-blocking connect is little complicate to use
*/
if (-1 == fcntl(cur_socket,F_SETFL,O_NONBLOCK)) {
int err = errno;
DPRINT(Debug,12,(&Debug,
"connect_remote_account: fcntl [O_NONBLOCK] failed: %s\n",
error_description(err)));
}
ra->stream = returnSimpleStream(cur_socket);
ra->service_idx = -1;
if (!(se->flags & SE_temporary)) {
ra->service_idx = se - service_list;
DPRINT(Debug,12,(&Debug,
"connect_remote_account: service_idx = %d\n",
ra->service_idx));
if (ra->service_idx < 0 || ra->service_idx >= service_count) {
panic("CONNECTION PANIC",__FILE__,__LINE__,
"connect_remote_account",
"Non-temporary service entry not in list",0);
}
}
clean:
DPRINT(Debug,12,(&Debug,
"connect_remote_account=%d\n",ok));
return ok;
}
/* -1 == name not found or bad syntax
0 == not a remote address
1 == name found
*/
int split_remote_name(name,X,se,rest,lookup_flags)
char *name;
struct remote_account *X;
struct service_entry **se;
char **rest;
int lookup_flags;
{
char *sep;
int ret = 0;
DPRINT(Debug,12,(&Debug,
"split_remote_name: name=\"%s\", lookup_flags=%d\n",
name,lookup_flags));
*rest = NULL;
zero_remote_account(X);
*se = NULL;
*rest = strpbrk(name,"/:");
sep = strchr(name,'@');
if (sep && (!*rest || *rest > sep)) {
char * sep2;
if (sep == name || sep[1] == '\0' ||
*rest == sep+1) {
lib_error(CATGETS(elm_msg_cat, MeSet,MeBadRemoteMailbox,
"Bad remote mailbox: %s"),
name);
ret = -1;
goto clean;
}
/* Test for '@' on hostname -- if there is, then
assume that first '@' was on username
*/
sep2 = strchr(sep+1,'@');
if (sep2 && (!*rest || *rest > sep2+1)) {
DPRINT(Debug,12,(&Debug,
"split_remote_name: Found second '@' from hostname, Assuming that first '@' was on username\n"));
sep = sep2;
}
if (*rest) {
CONST char * START = sep+1;
X->host = safe_malloc(*rest - START+1);
memcpy(X->host,START,*rest - START);
X->host[*rest - START] = '\0';
} else
X->host = safe_strdup(sep+1);
X->username = safe_malloc(sep - name+1);
memcpy(X->username,name,sep - name);
X->username[sep - name] = '\0';
if (0 == lookup_flags) {
lookup_flags = *rest ? STFLAG_browser : STFLAG_mbox;
DPRINT(Debug,12,(&Debug,
"split_remote_name: (%s) Using lookup_flags=%d\n",
name,lookup_flags));
}
*se = give_service_entry(X->host, lookup_flags);
if (!*se) {
ret = -1;
goto clean;
}
/* Canonify host name ... */
free(X->host);
X->host = safe_strdup((*se)->official_name);
DPRINT(Debug,12,(&Debug,
"split_remote_name: username=%s, host=%s\n",
X->username ? X->username : "<NULL>",
X->host ? X->host : "<NULL>"));
ret = 1;
}
clean:
DPRINT(Debug,12,(&Debug,
"split_remote_name=%d: *rest=%s\n",
ret,
*rest ? *rest : "<NULL>"));
return ret;
}
static struct connection_cache * CACHE_LIST = NULL;
/* May not be
uin16 port
because this is promoted to int
*/
struct connection_cache * locate_from_cache(username,host,con_type,port)
CONST char * username;
CONST char * host;
CONST struct connection_type *con_type;
int port; /* 0 == default port */
{
struct connection_cache * ptr;
for (ptr = CACHE_LIST; ptr; ptr = ptr -> next) {
if (!ptr->C.username || !ptr->C.host) {
DPRINT(Debug,11,(&Debug,
"locate_from_cache: %p: No host or username on cache!\n",
ptr));
continue;
}
if (0 == strcmp(username,ptr->C.username) &&
0 == istrcmp(host,ptr->C.host) &&
(!con_type || con_type == ptr->type) &&
port == ptr->port)
return ptr;
}
return NULL;
}
static void remove_from_cache P_((struct connection_cache *con,
int maybe));
static void remove_from_cache(con,maybe)
struct connection_cache *con;
int maybe;
{
struct connection_cache * ptr, *prev = NULL;
for (ptr = CACHE_LIST; ptr; prev=ptr, ptr = ptr -> next) {
if (ptr == con) {
if (NULL == prev)
CACHE_LIST = ptr->next;
else
prev->next = ptr->next;
ptr->next = NULL;
DPRINT(Debug,11,(&Debug,
"remove_from_cache: con=%p (%s@%s), type=%p (%s): removed from cache\n",
con,
con->C.username ? con->C.username : "<NULL>",
con->C.host ? con->C.host : "<NULL>",
con->type,
con->type->type_name));
return;
}
}
con->next = NULL;
if (maybe) {
DPRINT(Debug,11,(&Debug,
"remove_from_cache: con=%p (%s@%s), type=%p (%s): Not in cache\n",
con,
con->C.username ? con->C.username : "<NULL>",
con->C.host ? con->C.host : "<NULL>",
con->type,
con->type->type_name));
} else {
DPRINT(Debug,1,(&Debug,
"remove_from_cache: con=%p (%s@%s), type=%p: Not in cache\n",
con,
con->C.username ? con->C.username : "<NULL>",
con->C.host ? con->C.host : "<NULL>",
con->type));
panic("CONNECTION PANIC",__FILE__,__LINE__,"remove_from_cache",
"Connection not in connection cache",0);
}
}
struct connection_cache * create_connection(T)
struct connection_type *T;
{
struct connection_cache *ret;
if (CONNECTION_TYPE_magic != T->magic)
panic("REMOTE CONNECTION PANIC",__FILE__,__LINE__,
"create_connection",
"Bad connection type",0);
DPRINT(Debug,10,(&Debug,
"create_connection: type=%p (%s)\n",
T,T->type_name));
ret = safe_malloc(sizeof (*ret));
bzero((void *)ret,sizeof (*ret));
ret->type = T;
ret->next = NULL;
ret->f = NULL;
ret->d = NULL;
ret->state = CON_error;
ret->a.any = NULL; /* Initilize to NULL */
ret->port = 0; /* Default port */
zero_remote_account(&(ret->C));
ret->type->cache_zero_it(ret);
DPRINT(Debug,10,(&Debug,
"create_connection=%p\n",ret));
return ret;
}
void free_connection(c)
struct connection_cache **c;
{
if (CONNECTION_TYPE_magic != (*c)->type->magic)
panic("REMOTE CONNECTION PANIC",__FILE__,__LINE__,
"free_connection",
"Bad connection type",0);
DPRINT(Debug,10,(&Debug,
"free_connection: con=%p (%s@%s), type=%p (%s)\n",
(*c),
(*c)->C.username ? (*c)->C.username : "<NULL>",
(*c)->C.host ? (*c)->C.host : "<NULL>",
(*c)->type,
(*c)->type->type_name));
if (CACHE_LIST)
remove_from_cache((*c),1);
if (NULL != (*c)->C.stream &&
(*c)->state != CON_error)
(*c)->type->cache_close_it((*c));
(*c)->type->cache_free_it((*c));
free_remote_account(&((*c)->C));
(*c)->state = CON_error;
(*c)->f = NULL;
(*c)->d = NULL;
(*c)->next = NULL;
(*c)->type = NULL;
free(*c);
*c = NULL;
}
int join_connection(c,X,st)
struct connection_cache *c;
struct remote_account *X;
enum connection_state st;
{
int ret = 0;
DPRINT(Debug,10,(&Debug,
"join_connection: con=%p, type=%p (%s), X=%p (%s@%s), st=%d\n",
c,
c->type,
c->type->type_name,
X,
X->username ? X->username : "<NULL>",
X->host ? X->host : "<NULL>",
st));
if (CONNECTION_TYPE_magic != c->type->magic)
panic("REMOTE CONNECTION PANIC",__FILE__,__LINE__,
"join_connection",
"Bad connection type",0);
free_remote_account(&(c->C));
c->C = *X;
c->state = st;
/* Avoid double free() ... */
X->host = NULL;
X->username = NULL;
X->stream = NULL;
ret = c->type->cache_open_it(c);
DPRINT(Debug,10,(&Debug,
"join_connection=%d (state=%d)\n",
ret,c->state));
return ret;
}
int login_connection(c,password)
struct connection_cache *c;
CONST struct string *password; /* May be NULL */
{
int ret = 0;
if (CONNECTION_TYPE_magic != c->type->magic)
panic("REMOTE CONNECTION PANIC",__FILE__,__LINE__,
"login_connection",
"Bad connection type",0);
DPRINT(Debug,10,(&Debug,
"login_connection: con=%p (%s@%s), type=%p (%s)\n",
c,
c->C.username ? c->C.username : "<NULL>",
c->C.host ? c->C.host : "<NULL>",
c->type,c->type->type_name));
if (c->state != CON_open) {
DPRINT(Debug,10,(&Debug,
"login_connection: Opening it first...\n"));
ret = c->type->cache_open_it(c);
if (!ret)
goto fail;
}
ret = c->type->cache_login_it(c,password);
fail:
DPRINT(Debug,10,(&Debug,
"login_connection=%d\n",ret));
return ret;
}
void folder_from_connection(c,f)
struct connection_cache *c;
struct folder_info *f;
{
if (CONNECTION_TYPE_magic != c->type->magic)
panic("REMOTE CONNECTION PANIC",__FILE__,__LINE__,
"folder_from_connection",
"Bad connection type",0);
DPRINT(Debug,10,(&Debug,
"folder_from_connection: con=%p (%s@%s), type=%p (%s)\n",
c,
c->C.username ? c->C.username : "<NULL>",
c->C.host ? c->C.host : "<NULL>",
c->type,c->type->type_name));
DPRINT(Debug,10,(&Debug,
" : folder=%p\n",f));
/* Must have be on connection cache */
remove_from_cache(c,0);
c->f = f;
c->type->cache_folder_from_it(c,f);
}
void browser_from_connection(c,d)
struct connection_cache *c;
struct folder_browser *d;
{
if (CONNECTION_TYPE_magic != c->type->magic)
panic("REMOTE CONNECTION PANIC",__FILE__,__LINE__,
"browser_from_connection",
"Bad connection type",0);
DPRINT(Debug,10,(&Debug,
"browser_from_connection: con=%p (%s@%s), type=%p (%s)\n",
c,
c->C.username ? c->C.username : "<NULL>",
c->C.host ? c->C.host : "<NULL>",
c->type,c->type->type_name));
DPRINT(Debug,10,(&Debug,
" : browser=%p\n",d));
/* Must have be on connection cache */
remove_from_cache(c,0);
c->d = d;
c->type->cache_browser_from_it(c,d);
}
void close_connection(con)
struct connection_cache *con;
{
if (CONNECTION_TYPE_magic != con->type->magic)
panic("REMOTE CONNECTION PANIC",__FILE__,__LINE__,
"close_connection",
"Bad connection type",0);
DPRINT(Debug,10,(&Debug,
"close_connection: con=%p (%s@%s), type=%p (%s)\n",
con,
con->C.username ? con->C.username : "<NULL>",
con->C.host ? con->C.host : "<NULL>",
con->type,con->type->type_name));
con->type->cache_close_it(con);
if (NULL != con->C.stream ) {
DPRINT(Debug,10,(&Debug,
"close_connection: Closing socket\n"));
FreeStreamStack( &(con->C.stream));
}
con->state = CON_error;
}
int close_cached_connections()
{
struct connection_cache * ptr, *next;
int X = 0;
DPRINT(Debug,4,(&Debug,
"Closing cached connections...\n"));
for (ptr = CACHE_LIST; ptr; ptr = next) {
next = ptr -> next;
close_connection(ptr);
X++;
free_connection(&ptr);
}
DPRINT(Debug,4,(&Debug,
"Cached connections closed\n"));
return X;
}
void cache_connection(c)
struct connection_cache *c;
{
if (CONNECTION_TYPE_magic != c->type->magic)
panic("REMOTE CONNECTION PANIC",__FILE__,__LINE__,
"cache_connection",
"Bad connection type",0);
DPRINT(Debug,10,(&Debug,
"cache_connection: con=%p (%s@%s), type=%p (%s)\n",
c,
c->C.username ? c->C.username : "<NULL>",
c->C.host ? c->C.host : "<NULL>",
c->type,c->type->type_name));
c->f = NULL; /* Detach from folder */
c->d = NULL; /* Detach from browser */
c->next = CACHE_LIST;
CACHE_LIST = c;
}
#endif
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1