コード例 #1
0
ファイル: control.c プロジェクト: henri14/citadel
/*
 * check_control   -  check the control record has sensible values for message, user and room numbers
 */
void check_control(void)
{
	syslog(LOG_INFO, "Checking/re-building control record\n");
	get_control();
	// Find highest room number and message number.
	CtdlForEachRoom(control_find_highest, NULL);
	ForEachUser(control_find_user, NULL);
	put_control();
}
コード例 #2
0
ファイル: control.c プロジェクト: henri14/citadel
/*
 * get_new_room_number()  -  Obtain a new, unique ID to be used for a room.
 */
long get_new_room_number(void)
{
	long retval = 0L;
	begin_critical_section(S_CONTROL);
	get_control();
	retval = ++CitControl.MMnextroom;
	put_control();
	end_critical_section(S_CONTROL);
	return(retval);
}
コード例 #3
0
ファイル: control.c プロジェクト: henri14/citadel
/*
 * get_new_message_number()  -  Obtain a new, unique ID to be used for a message.
 */
long get_new_message_number(void)
{
	long retval = 0L;
	begin_critical_section(S_CONTROL);
	get_control();
	retval = ++CitControl.MMhighest;
	put_control();
	end_critical_section(S_CONTROL);
	return(retval);
}
コード例 #4
0
/***********
 * Put a packet into the jitterbuffers 
 * Only the timestamps of voicepackets are put in the history
 * this because the jitterbuffer only works for voicepackets
 * don't put packets twice in history and queue (e.g. transmitting every frame twice)
 * keep track of statistics
 */
void jb_put(jitterbuffer *jb, void *data, int type, long ms, long ts, long now, int codec) 
{ 
  long pointer, max_index;
  
  if (jb == NULL) {
    jb_err("no jitterbuffer in jb_put()\n");
    return;
  }
  
  jb->info.frames_received++;

  if (type == JB_TYPE_CONTROL) {
    //put the packet into the contol-queue of the jitterbuffer
    jb_dbg("pC");
    put_control(jb,data,type,ts);

  } else if (type == JB_TYPE_VOICE) {
    // only add voice that aren't already in the buffer
    max_index = (jb->hist_pointer < JB_HISTORY_SIZE) ? jb->hist_pointer : JB_HISTORY_SIZE-1;
    pointer = find_pointer(&jb->hist_sorted_timestamp[0], max_index, ts);
    if (jb->hist_sorted_timestamp[pointer]==ts) { //timestamp already in queue
      jb_dbg("pT");
      free(data); 
      jb->info.frames_dropped_twice++;
    } else { //add
      jb_dbg("pV");
      /* add voicepacket to history */
      put_history(jb,ts,now,ms,codec);
      /*calculate jitterbuffer size*/
      calculate_info(jb, ts, now, codec);
      /*put the packet into the queue of the jitterbuffer*/
      put_voice(jb,data,type,ms,ts,codec);
    } 

  } else if (type == JB_TYPE_SILENCE){ //silence
    jb_dbg("pS");
    put_voice(jb,data,type,ms,ts,codec);

  } else {//should NEVER happen
    jb_err("jb_put(): type not known\n");
    free(data);
  }
}
コード例 #5
0
ファイル: control.c プロジェクト: henri14/citadel
/* 
 * Get or set global configuration options
 *
 * IF YOU ADD OR CHANGE FIELDS HERE, YOU *MUST* DOCUMENT YOUR CHANGES AT:
 * http://www.citadel.org/doku.php?id=documentation:applicationprotocol
 *
 */
void cmd_conf(char *argbuf)
{
	char cmd[16];
	char buf[256];
	int a;
	char *confptr;
	char confname[128];

	if (CtdlAccessCheck(ac_aide)) return;

	extract_token(cmd, argbuf, 0, '|', sizeof cmd);
	if (!strcasecmp(cmd, "GET")) {
		cprintf("%d Configuration...\n", LISTING_FOLLOWS);
		cprintf("%s\n", config.c_nodename);
		cprintf("%s\n", config.c_fqdn);
		cprintf("%s\n", config.c_humannode);
		cprintf("%s\n", config.c_phonenum);
		cprintf("%d\n", config.c_creataide);
		cprintf("%d\n", config.c_sleeping);
		cprintf("%d\n", config.c_initax);
		cprintf("%d\n", config.c_regiscall);
		cprintf("%d\n", config.c_twitdetect);
		cprintf("%s\n", config.c_twitroom);
		cprintf("%s\n", config.c_moreprompt);
		cprintf("%d\n", config.c_restrict);
		cprintf("%s\n", config.c_site_location);
		cprintf("%s\n", config.c_sysadm);
		cprintf("%d\n", config.c_maxsessions);
		cprintf("xxx\n"); /* placeholder -- field no longer in use */
		cprintf("%d\n", config.c_userpurge);
		cprintf("%d\n", config.c_roompurge);
		cprintf("%s\n", config.c_logpages);
		cprintf("%d\n", config.c_createax);
		cprintf("%ld\n", config.c_maxmsglen);
		cprintf("%d\n", config.c_min_workers);
		cprintf("%d\n", config.c_max_workers);
		cprintf("%d\n", config.c_pop3_port);
		cprintf("%d\n", config.c_smtp_port);
		cprintf("%d\n", config.c_rfc822_strict_from);
		cprintf("%d\n", config.c_aide_zap);
		cprintf("%d\n", config.c_imap_port);
		cprintf("%ld\n", config.c_net_freq);
		cprintf("%d\n", config.c_disable_newu);
		cprintf("1\n");	/* niu */
		cprintf("%d\n", config.c_purge_hour);
#ifdef HAVE_LDAP
		cprintf("%s\n", config.c_ldap_host);
		cprintf("%d\n", config.c_ldap_port);
		cprintf("%s\n", config.c_ldap_base_dn);
		cprintf("%s\n", config.c_ldap_bind_dn);
		cprintf("%s\n", config.c_ldap_bind_pw);
#else
		cprintf("\n");
		cprintf("0\n");
		cprintf("\n");
		cprintf("\n");
		cprintf("\n");
#endif
		cprintf("%s\n", config.c_ip_addr);
		cprintf("%d\n", config.c_msa_port);
		cprintf("%d\n", config.c_imaps_port);
		cprintf("%d\n", config.c_pop3s_port);
		cprintf("%d\n", config.c_smtps_port);
		cprintf("%d\n", config.c_enable_fulltext);
		cprintf("%d\n", config.c_auto_cull);
		cprintf("1\n");
		cprintf("%d\n", config.c_allow_spoofing);
		cprintf("%d\n", config.c_journal_email);
		cprintf("%d\n", config.c_journal_pubmsgs);
		cprintf("%s\n", config.c_journal_dest);
		cprintf("%s\n", config.c_default_cal_zone);
		cprintf("%d\n", config.c_pftcpdict_port);
		cprintf("%d\n", config.c_managesieve_port);
	        cprintf("%d\n", config.c_auth_mode);
	        cprintf("%s\n", config.c_funambol_host);
	        cprintf("%d\n", config.c_funambol_port);
	        cprintf("%s\n", config.c_funambol_source);
	        cprintf("%s\n", config.c_funambol_auth);
		cprintf("%d\n", config.c_rbl_at_greeting);
		cprintf("%s\n", config.c_master_user);
		cprintf("%s\n", config.c_master_pass);
		cprintf("%s\n", config.c_pager_program);
		cprintf("%d\n", config.c_imap_keep_from);
		cprintf("%d\n", config.c_xmpp_c2s_port);
		cprintf("%d\n", config.c_xmpp_s2s_port);
		cprintf("%ld\n", config.c_pop3_fetch);
		cprintf("%ld\n", config.c_pop3_fastest);
		cprintf("%d\n", config.c_spam_flag_only);
		cprintf("%d\n", config.c_guest_logins);
		cprintf("%d\n", config.c_port_number);
		cprintf("%d\n", config.c_ctdluid);
		cprintf("%d\n", config.c_nntp_port);
		cprintf("%d\n", config.c_nntps_port);
		cprintf("000\n");
	}

	else if (!strcasecmp(cmd, "SET")) {
		unbuffer_output();
		cprintf("%d Send configuration...\n", SEND_LISTING);
		a = 0;
		while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
			switch (a) {
			case 0:
				configlen.c_nodename = safestrncpy(config.c_nodename, buf,
								   sizeof config.c_nodename);
				break;
			case 1:
				configlen.c_fqdn = safestrncpy(config.c_fqdn, buf,
							       sizeof config.c_fqdn);
				break;
			case 2:
				configlen.c_humannode = safestrncpy(config.c_humannode, buf,
								    sizeof config.c_humannode);
				break;
			case 3:
				configlen.c_phonenum = safestrncpy(config.c_phonenum, buf,
								   sizeof config.c_phonenum);
				break;
			case 4:
				config.c_creataide = atoi(buf);
				break;
			case 5:
				config.c_sleeping = atoi(buf);
				break;
			case 6:
				config.c_initax = atoi(buf);
				if (config.c_initax < 1)
					config.c_initax = 1;
				if (config.c_initax > 6)
					config.c_initax = 6;
				break;
			case 7:
				config.c_regiscall = atoi(buf);
				if (config.c_regiscall != 0)
					config.c_regiscall = 1;
				break;
			case 8:
				config.c_twitdetect = atoi(buf);
				if (config.c_twitdetect != 0)
					config.c_twitdetect = 1;
				break;
			case 9:
				configlen.c_twitroom = safestrncpy(config.c_twitroom, buf,
								   sizeof config.c_twitroom);
				break;
			case 10:
				configlen.c_moreprompt = safestrncpy(config.c_moreprompt, buf,
								     sizeof config.c_moreprompt);
				break;
			case 11:
				config.c_restrict = atoi(buf);
				if (config.c_restrict != 0)
					config.c_restrict = 1;
				break;
			case 12:
				configlen.c_site_location = safestrncpy(
					config.c_site_location, buf,
					sizeof config.c_site_location);
				break;
			case 13:
				configlen.c_sysadm = safestrncpy(config.c_sysadm, buf,
								 sizeof config.c_sysadm);
				break;
			case 14:
				config.c_maxsessions = atoi(buf);
				if (config.c_maxsessions < 0)
					config.c_maxsessions = 0;
				break;
			case 15:
				/* placeholder -- field no longer in use */
				break;
			case 16:
				config.c_userpurge = atoi(buf);
				break;
			case 17:
				config.c_roompurge = atoi(buf);
				break;
			case 18:
				configlen.c_logpages = safestrncpy(config.c_logpages, buf,
								   sizeof config.c_logpages);
				break;
			case 19:
				config.c_createax = atoi(buf);
				if (config.c_createax < 1)
					config.c_createax = 1;
				if (config.c_createax > 6)
					config.c_createax = 6;
				break;
			case 20:
				if (atoi(buf) >= 8192)
					config.c_maxmsglen = atoi(buf);
				break;
			case 21:
				if (atoi(buf) >= 2)
					config.c_min_workers = atoi(buf);
			case 22:
				if (atoi(buf) >= config.c_min_workers)
					config.c_max_workers = atoi(buf);
			case 23:
				config.c_pop3_port = atoi(buf);
				break;
			case 24:
				config.c_smtp_port = atoi(buf);
				break;
			case 25:
				config.c_rfc822_strict_from = atoi(buf);
				break;
			case 26:
				config.c_aide_zap = atoi(buf);
				if (config.c_aide_zap != 0)
					config.c_aide_zap = 1;
				break;
			case 27:
				config.c_imap_port = atoi(buf);
				break;
			case 28:
				config.c_net_freq = atol(buf);
				break;
			case 29:
				config.c_disable_newu = atoi(buf);
				if (config.c_disable_newu != 0)
					config.c_disable_newu = 1;
				break;
			case 30:
				/* niu */
				break;
			case 31:
				if ((config.c_purge_hour >= 0)
				    && (config.c_purge_hour <= 23)) {
					config.c_purge_hour = atoi(buf);
				}
				break;
#ifdef HAVE_LDAP
			case 32:
				configlen.c_ldap_host = safestrncpy(config.c_ldap_host, buf,
								    sizeof config.c_ldap_host);
				break;
			case 33:
				config.c_ldap_port = atoi(buf);
				break;
			case 34:
				configlen.c_ldap_base_dn = safestrncpy(config.c_ldap_base_dn, buf,
								       sizeof config.c_ldap_base_dn);
				break;
			case 35:
				configlen.c_ldap_bind_dn = safestrncpy(config.c_ldap_bind_dn, buf,
								       sizeof config.c_ldap_bind_dn);
				break;
			case 36:
				configlen.c_ldap_bind_pw = safestrncpy(config.c_ldap_bind_pw, buf,
								       sizeof config.c_ldap_bind_pw);
				break;
#endif
			case 37:
				configlen.c_ip_addr = safestrncpy(config.c_ip_addr, buf,
								  sizeof config.c_ip_addr);
			case 38:
				config.c_msa_port = atoi(buf);
				break;
			case 39:
				config.c_imaps_port = atoi(buf);
				break;
			case 40:
				config.c_pop3s_port = atoi(buf);
				break;
			case 41:
				config.c_smtps_port = atoi(buf);
				break;
			case 42:
				config.c_enable_fulltext = atoi(buf);
				break;
			case 43:
				config.c_auto_cull = atoi(buf);
				break;
			case 44:
				/* niu */
				break;
			case 45:
				config.c_allow_spoofing = atoi(buf);
				break;
			case 46:
				config.c_journal_email = atoi(buf);
				break;
			case 47:
				config.c_journal_pubmsgs = atoi(buf);
				break;
			case 48:
				configlen.c_journal_dest = safestrncpy(config.c_journal_dest, buf,
								       sizeof config.c_journal_dest);
			case 49:
				configlen.c_default_cal_zone = safestrncpy(
					config.c_default_cal_zone, buf,
					sizeof config.c_default_cal_zone);
				break;
			case 50:
				config.c_pftcpdict_port = atoi(buf);
				break;
			case 51:
				config.c_managesieve_port = atoi(buf);
				break;
			case 52:
				config.c_auth_mode = atoi(buf);
			case 53:
				configlen.c_funambol_host = safestrncpy(
					config.c_funambol_host, buf,
					sizeof config.c_funambol_host);
				break;
			case 54:
				config.c_funambol_port = atoi(buf);
				break;
			case 55:
				configlen.c_funambol_source = safestrncpy(
					config.c_funambol_source, buf, 
					sizeof config.c_funambol_source);
				break;
			case 56:
				configlen.c_funambol_auth = safestrncpy(
					config.c_funambol_auth, buf,
					sizeof config.c_funambol_auth);
				break;
			case 57:
				config.c_rbl_at_greeting = atoi(buf);
				break;
			case 58:
				configlen.c_master_user = safestrncpy(
					config.c_master_user,
					buf, sizeof config.c_master_user);
				break;
			case 59:
				configlen.c_master_pass = safestrncpy(
					config.c_master_pass, buf, sizeof config.c_master_pass);
				break;
			case 60:
				configlen.c_pager_program = safestrncpy(
					config.c_pager_program,	buf, sizeof config.c_pager_program);
				break;
			case 61:
				config.c_imap_keep_from = atoi(buf);
				break;
			case 62:
				config.c_xmpp_c2s_port = atoi(buf);
				break;
			case 63:
				config.c_xmpp_s2s_port = atoi(buf);
				break;
			case 64:
				config.c_pop3_fetch = atol(buf);
				break;
			case 65:
				config.c_pop3_fastest = atol(buf);
				break;
			case 66:
				config.c_spam_flag_only = atoi(buf);
				break;
			case 67:
				config.c_guest_logins = atoi(buf);
				break;
			case 68:
				config.c_port_number = atoi(buf);
				break;
			case 69:
				config.c_ctdluid = atoi(buf);
				break;
			case 70:
				config.c_nntp_port = atoi(buf);
				break;
			case 71:
				config.c_nntps_port = atoi(buf);
				break;
			}
			++a;
		}
		put_config();
		snprintf(buf, sizeof buf,
			"The global system configuration has been edited by %s.\n",
			 (CC->logged_in ? CC->curr_user : "******")
		);
		CtdlAideMessage(buf,"Citadel Configuration Manager Message");

		if (!IsEmptyStr(config.c_logpages))
			CtdlCreateRoom(config.c_logpages, 3, "", 0, 1, 1, VIEW_BBS);

		/* If full text indexing has been disabled, invalidate the
		 * index so it doesn't try to use it later.
		 */
		if (config.c_enable_fulltext == 0) {
			CitControl.fulltext_wordbreaker = 0;
			put_control();
		}
	}

	else if (!strcasecmp(cmd, "GETSYS")) {
		extract_token(confname, argbuf, 1, '|', sizeof confname);
		confptr = CtdlGetSysConfig(confname);
		if (confptr != NULL) {
			long len; 

			len = strlen(confptr);
			cprintf("%d %s\n", LISTING_FOLLOWS, confname);
			client_write(confptr, len);
			if ((len > 0) && (confptr[len - 1] != 10))
				client_write("\n", 1);
			cprintf("000\n");
			free(confptr);
		} else {
			cprintf("%d No such configuration.\n",
				ERROR + ILLEGAL_VALUE);
		}
	}

	else if (!strcasecmp(cmd, "PUTSYS")) {
		extract_token(confname, argbuf, 1, '|', sizeof confname);
		unbuffer_output();
		cprintf("%d %s\n", SEND_LISTING, confname);
		confptr = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
		CtdlPutSysConfig(confname, confptr);
		free(confptr);
	}

	else {
		cprintf("%d Illegal option(s) specified.\n",
			ERROR + ILLEGAL_VALUE);
	}
}
コード例 #6
0
ファイル: serv_fulltext.c プロジェクト: henri14/citadel
/*
 * Begin the fulltext indexing process.
 */
void do_fulltext_indexing(void) {
	int i;
	static time_t last_index = 0L;
	static time_t last_progress = 0L;
	time_t run_time = 0L;
	time_t end_time = 0L;
	static int is_running = 0;
	if (is_running) return;         /* Concurrency check - only one can run */
	is_running = 1;
	
	/*
	 * Don't do this if the site doesn't have it enabled.
	 */
	if (!config.c_enable_fulltext) {
		return;
	}

	/*
	 * Make sure we don't run the indexer too frequently.
	 * FIXME move the setting into config
	 */
 
	if ( (time(NULL) - last_index) < 300L) {
		return;
	}

	/*
	 * Check to see whether the fulltext index is up to date; if there
	 * are no messages to index, don't waste any more time trying.
	 */
	if ((CitControl.MMfulltext >= CitControl.MMhighest) && (CitControl.fulltext_wordbreaker == FT_WORDBREAKER_ID)) {
		return;		/* nothing to do! */
	}
	
	run_time = time(NULL);
	syslog(LOG_DEBUG, "do_fulltext_indexing() started (%ld)", run_time);
	
	/*
	 * If we've switched wordbreaker modules, burn the index and start
	 * over.
	 */
	begin_critical_section(S_CONTROL);
	if (CitControl.fulltext_wordbreaker != FT_WORDBREAKER_ID) {
		syslog(LOG_DEBUG, "wb ver on disk = %d, code ver = %d",
			CitControl.fulltext_wordbreaker, FT_WORDBREAKER_ID
		);
		syslog(LOG_INFO, "(re)initializing full text index");
		cdb_trunc(CDB_FULLTEXT);
		CitControl.MMfulltext = 0L;
		put_control();
	}
	end_critical_section(S_CONTROL);

	/*
	 * Now go through each room and find messages to index.
	 */
	ft_newhighest = CitControl.MMhighest;
	CtdlForEachRoom(ft_index_room, NULL);	/* load all msg pointers */

	if (ft_num_msgs > 0) {
		qsort(ft_newmsgs, ft_num_msgs, sizeof(long), longcmp);
		for (i=0; i<(ft_num_msgs-1); ++i) { /* purge dups */
			if (ft_newmsgs[i] == ft_newmsgs[i+1]) {
				memmove(&ft_newmsgs[i], &ft_newmsgs[i+1],
					((ft_num_msgs - i - 1)*sizeof(long)));
				--ft_num_msgs;
				--i;
			}
		}

		/* Here it is ... do each message! */
		for (i=0; i<ft_num_msgs; ++i) {
			if (time(NULL) != last_progress) {
				syslog(LOG_DEBUG,
					"Indexed %d of %d messages (%d%%)",
						i, ft_num_msgs,
						((i*100) / ft_num_msgs)
				);
				last_progress = time(NULL);
			}
			ft_index_message(ft_newmsgs[i], 1);

			/* Check to see if we need to quit early */
			if (server_shutting_down) {
				syslog(LOG_DEBUG, "Indexer quitting early");
				ft_newhighest = ft_newmsgs[i];
				break;
			}

			/* Check to see if we have to maybe flush to disk */
			if (i >= FT_MAX_CACHE) {
				syslog(LOG_DEBUG, "Time to flush.");
				ft_newhighest = ft_newmsgs[i];
				break;
			}

		}

		free(ft_newmsgs);
		ft_num_msgs = 0;
		ft_num_alloc = 0;
		ft_newmsgs = NULL;
	}
	end_time = time(NULL);

	if (server_shutting_down) {
		is_running = 0;
		return;
	}
	
	syslog(LOG_DEBUG, "do_fulltext_indexing() duration (%ld)", end_time - run_time);
		
	/* Save our place so we don't have to do this again */
	ft_flush_cache();
	begin_critical_section(S_CONTROL);
	CitControl.MMfulltext = ft_newhighest;
	CitControl.fulltext_wordbreaker = FT_WORDBREAKER_ID;
	put_control();
	end_critical_section(S_CONTROL);
	last_index = time(NULL);

	syslog(LOG_DEBUG, "do_fulltext_indexing() finished");
	is_running = 0;
	return;
}
コード例 #7
0
ファイル: database.c プロジェクト: henri14/citadel
/*
 * Open the various databases we'll be using.  Any database which
 * does not exist should be created.  Note that we don't need a
 * critical section here, because there aren't any active threads
 * manipulating the database yet.
 */
void open_databases(void)
{
	int ret;
	int i;
	char dbfilename[32];
	u_int32_t flags = 0;
	int dbversion_major, dbversion_minor, dbversion_patch;
	int current_dbversion = 0;

	syslog(LOG_DEBUG, "bdb(): open_databases() starting");
	syslog(LOG_DEBUG, "Compiled db: %s", DB_VERSION_STRING);
	syslog(LOG_INFO, "  Linked db: %s",
		db_version(&dbversion_major, &dbversion_minor, &dbversion_patch));

	current_dbversion = (dbversion_major * 1000000) + (dbversion_minor * 1000) + dbversion_patch;

	syslog(LOG_DEBUG, "Calculated dbversion: %d", current_dbversion);
	syslog(LOG_DEBUG, "  Previous dbversion: %d", CitControl.MMdbversion);

	if ( (getenv("SUPPRESS_DBVERSION_CHECK") == NULL)
	   && (CitControl.MMdbversion > current_dbversion) ) {
		syslog(LOG_EMERG, "You are attempting to run the Citadel server using a version");
		syslog(LOG_EMERG, "of Berkeley DB that is older than that which last created or");
		syslog(LOG_EMERG, "updated the database.  Because this would probably cause data");
		syslog(LOG_EMERG, "corruption or loss, the server is aborting execution now.");
		exit(CTDLEXIT_DB);
	}

	CitControl.MMdbversion = current_dbversion;
	put_control();

	syslog(LOG_INFO, "Linked zlib: %s\n", zlibVersion());

	/*
	 * Silently try to create the database subdirectory.  If it's
	 * already there, no problem.
	 */
	if ((mkdir(ctdl_data_dir, 0700) != 0) && (errno != EEXIST)){
		syslog(LOG_EMERG, 
			      "unable to create database directory [%s]: %s", 
			      ctdl_data_dir, strerror(errno));
	}
	if (chmod(ctdl_data_dir, 0700) != 0){
		syslog(LOG_EMERG, 
			      "unable to set database directory accessrights [%s]: %s", 
			      ctdl_data_dir, strerror(errno));
	}
	if (chown(ctdl_data_dir, CTDLUID, (-1)) != 0){
		syslog(LOG_EMERG, 
			      "unable to set the owner for [%s]: %s", 
			      ctdl_data_dir, strerror(errno));
	}
	syslog(LOG_DEBUG, "bdb(): Setting up DB environment\n");
	/* db_env_set_func_yield((int (*)(u_long,  u_long))sched_yield); */
	ret = db_env_create(&dbenv, 0);
	if (ret) {
		syslog(LOG_EMERG, "bdb(): db_env_create: %s\n", db_strerror(ret));
		syslog(LOG_EMERG, "exit code %d\n", ret);
		exit(CTDLEXIT_DB);
	}
	dbenv->set_errpfx(dbenv, "citserver");
	dbenv->set_paniccall(dbenv, dbpanic);
	dbenv->set_errcall(dbenv, cdb_verbose_err);
	dbenv->set_errpfx(dbenv, "ctdl");
#if (DB_VERSION_MAJOR == 4) && (DB_VERSION_MINOR >= 3)
	dbenv->set_msgcall(dbenv, cdb_verbose_log);
#endif
	dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK, 1);
	dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 1);

	/*
	 * We want to specify the shared memory buffer pool cachesize,
	 * but everything else is the default.
	 */
	ret = dbenv->set_cachesize(dbenv, 0, 64 * 1024, 0);
	if (ret) {
		syslog(LOG_EMERG, "bdb(): set_cachesize: %s\n", db_strerror(ret));
		dbenv->close(dbenv, 0);
		syslog(LOG_EMERG, "exit code %d\n", ret);
		exit(CTDLEXIT_DB);
	}

	if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT))) {
		syslog(LOG_EMERG, "bdb(): set_lk_detect: %s\n", db_strerror(ret));
		dbenv->close(dbenv, 0);
		syslog(LOG_EMERG, "exit code %d\n", ret);
		exit(CTDLEXIT_DB);
	}

	flags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_INIT_TXN | DB_INIT_LOCK | DB_THREAD | DB_RECOVER;
	syslog(LOG_DEBUG, "dbenv->open(dbenv, %s, %d, 0)\n", ctdl_data_dir, flags);
	ret = dbenv->open(dbenv, ctdl_data_dir, flags, 0);
	if (ret == DB_RUNRECOVERY) {
		syslog(LOG_ALERT, "dbenv->open: %s\n", db_strerror(ret));
		syslog(LOG_ALERT, "Attempting recovery...\n");
		flags |= DB_RECOVER;
		ret = dbenv->open(dbenv, ctdl_data_dir, flags, 0);
	}
	if (ret == DB_RUNRECOVERY) {
		syslog(LOG_ALERT, "dbenv->open: %s\n", db_strerror(ret));
		syslog(LOG_ALERT, "Attempting catastrophic recovery...\n");
		flags &= ~DB_RECOVER;
		flags |= DB_RECOVER_FATAL;
		ret = dbenv->open(dbenv, ctdl_data_dir, flags, 0);
	}
	if (ret) {
		syslog(LOG_EMERG, "dbenv->open: %s\n", db_strerror(ret));
		dbenv->close(dbenv, 0);
		syslog(LOG_EMERG, "exit code %d\n", ret);
		exit(CTDLEXIT_DB);
	}

	syslog(LOG_INFO, "Starting up DB\n");

	for (i = 0; i < MAXCDB; ++i) {

		/* Create a database handle */
		ret = db_create(&dbp[i], dbenv, 0);
		if (ret) {
			syslog(LOG_EMERG, "db_create: %s\n", db_strerror(ret));
			syslog(LOG_EMERG, "exit code %d\n", ret);
			exit(CTDLEXIT_DB);
		}


		/* Arbitrary names for our tables -- we reference them by
		 * number, so we don't have string names for them.
		 */
		snprintf(dbfilename, sizeof dbfilename, "cdb.%02x", i);

		ret = dbp[i]->open(dbp[i],
				   NULL,
				   dbfilename,
				   NULL,
				   DB_BTREE,
				   DB_CREATE | DB_AUTO_COMMIT | DB_THREAD,
				   0600
		);
		if (ret) {
			syslog(LOG_EMERG, "db_open[%02x]: %s\n", i, db_strerror(ret));
			if (ret == ENOMEM) {
				syslog(LOG_EMERG, "You may need to tune your database; please read http://www.citadel.org/doku.php?id=faq:troubleshooting:out_of_lock_entries for more information.");
			}
			syslog(LOG_EMERG, "exit code %d\n", ret);
			exit(CTDLEXIT_DB);
		}
	}

}