4 * This module handles states which are global to the entire server.
15 #if TIME_WITH_SYS_TIME
16 # include <sys/time.h>
20 # include <sys/time.h>
30 #include <sys/types.h>
32 #include <libcitadel.h>
36 #include "sysdep_decls.h"
40 #include "citserver.h"
50 struct CitControl CitControl
;
51 extern struct config config
;
52 FILE *control_fp
= NULL
;
53 long control_highest_user
= 0;
57 * lock_control - acquire a lock on the control record file.
58 * This keeps multiple citservers from running concurrently.
60 void lock_control(void)
64 * TODO: solaris manpages describe this function, but the headers
68 if (flock(fileno(control_fp
), (LOCK_EX
| LOCK_NB
))) {
69 CtdlLogPrintf(CTDL_EMERG
, "citserver: unable to lock %s.\n", file_citadel_control
);
70 CtdlLogPrintf(CTDL_EMERG
, "Is another citserver already running?\n");
71 exit(CTDLEXIT_CONTROL
);
77 * callback to get highest room number when rebuilding control file
79 void control_find_highest(struct ctdlroom
*qrbuf
, void *data
)
82 struct cdbdata
*cdbfr
;
87 int message_fixed
= 0;
89 if (qrbuf
->QRnumber
> CitControl
.MMnextroom
)
91 CitControl
.MMnextroom
= qrbuf
->QRnumber
;
95 getroom (&room
, qrbuf
->QRname
);
97 /* Load the message list */
98 cdbfr
= cdb_fetch(CDB_MSGLISTS
, &room
.QRnumber
, sizeof(long));
100 msglist
= (long *) cdbfr
->ptr
;
101 num_msgs
= cdbfr
->len
/ sizeof(long);
103 return; /* No messages at all? No further action. */
108 for (c
=0; c
<num_msgs
; c
++)
110 if (msglist
[c
] > CitControl
.MMhighest
)
112 CitControl
.MMhighest
= msglist
[c
];
119 CtdlLogPrintf(CTDL_INFO
, "Control record checking....Fixed room counter\n");
121 CtdlLogPrintf(CTDL_INFO
, "Control record checking....Fixed message count\n");
127 * Callback to get highest user number.
130 void control_find_user (struct ctdluser
*EachUser
, void *out_data
)
134 if (EachUser
->usernum
> CitControl
.MMnextuser
)
136 CitControl
.MMnextuser
= EachUser
->usernum
;
140 CtdlLogPrintf(CTDL_INFO
, "Control record checking....Fixed user count\n");
145 * get_control - read the control record into memory.
147 void get_control(void)
149 static int already_have_control
= 0;
152 * If we already have the control record in memory, there's no point
153 * in reading it from disk again.
155 if (already_have_control
) return;
157 /* Zero it out. If the control record on disk is missing or short,
158 * the system functions with all control record fields initialized
161 memset(&CitControl
, 0, sizeof(struct CitControl
));
162 if (control_fp
== NULL
) {
163 control_fp
= fopen(file_citadel_control
, "rb+");
164 if (control_fp
!= NULL
) {
166 fchown(fileno(control_fp
), config
.c_ctdluid
, -1);
169 if (control_fp
== NULL
) {
170 control_fp
= fopen(file_citadel_control
, "wb+");
171 if (control_fp
!= NULL
) {
173 fchown(fileno(control_fp
), config
.c_ctdluid
, -1);
174 memset(&CitControl
, 0, sizeof(struct CitControl
));
175 fwrite(&CitControl
, sizeof(struct CitControl
),
180 if (control_fp
== NULL
) {
181 CtdlLogPrintf(CTDL_ALERT
, "ERROR opening %s: %s\n",
182 file_citadel_control
,
188 fread(&CitControl
, sizeof(struct CitControl
), 1, control_fp
);
189 already_have_control
= 1;
190 chown(file_citadel_control
, config
.c_ctdluid
, (-1));
194 * put_control - write the control record to disk.
196 void put_control(void)
199 if (control_fp
!= NULL
) {
201 fwrite(&CitControl
, sizeof(struct CitControl
), 1,
209 * check_control - check the control record has sensible values for message, user and room numbers
211 void check_control(void)
213 CtdlLogPrintf(CTDL_INFO
, "Checking/re-building control record\n");
215 // Find highest room number and message number.
216 ForEachRoom(control_find_highest
, NULL
);
217 ForEachUser(control_find_user
, NULL
);
223 * release_control - close our fd on exit
225 void release_control(void)
227 if (control_fp
!= NULL
)
233 * get_new_message_number() - Obtain a new, unique ID to be used for a message.
235 long get_new_message_number(void)
238 begin_critical_section(S_CONTROL
);
240 retval
= ++CitControl
.MMhighest
;
242 end_critical_section(S_CONTROL
);
248 * CtdlGetCurrentMessageNumber() - Obtain the current highest message number in the system
249 * This provides a quick way to initialise a variable that might be used to indicate
250 * messages that should not be processed. EG. a new Sieve script will use this
251 * to record determine that messages older than this should not be processed.
253 long CtdlGetCurrentMessageNumber(void)
256 begin_critical_section(S_CONTROL
);
258 retval
= CitControl
.MMhighest
;
259 end_critical_section(S_CONTROL
);
265 * get_new_user_number() - Obtain a new, unique ID to be used for a user.
267 long get_new_user_number(void)
270 begin_critical_section(S_CONTROL
);
272 retval
= ++CitControl
.MMnextuser
;
274 end_critical_section(S_CONTROL
);
281 * get_new_room_number() - Obtain a new, unique ID to be used for a room.
283 long get_new_room_number(void)
286 begin_critical_section(S_CONTROL
);
288 retval
= ++CitControl
.MMnextroom
;
290 end_critical_section(S_CONTROL
);
297 * Get or set global configuration options
299 void cmd_conf(char *argbuf
)
307 if (CtdlAccessCheck(ac_aide
)) return;
309 extract_token(cmd
, argbuf
, 0, '|', sizeof cmd
);
310 if (!strcasecmp(cmd
, "GET")) {
311 cprintf("%d Configuration...\n", LISTING_FOLLOWS
);
312 cprintf("%s\n", config
.c_nodename
);
313 cprintf("%s\n", config
.c_fqdn
);
314 cprintf("%s\n", config
.c_humannode
);
315 cprintf("%s\n", config
.c_phonenum
);
316 cprintf("%d\n", config
.c_creataide
);
317 cprintf("%d\n", config
.c_sleeping
);
318 cprintf("%d\n", config
.c_initax
);
319 cprintf("%d\n", config
.c_regiscall
);
320 cprintf("%d\n", config
.c_twitdetect
);
321 cprintf("%s\n", config
.c_twitroom
);
322 cprintf("%s\n", config
.c_moreprompt
);
323 cprintf("%d\n", config
.c_restrict
);
324 cprintf("%s\n", config
.c_site_location
);
325 cprintf("%s\n", config
.c_sysadm
);
326 cprintf("%d\n", config
.c_maxsessions
);
327 cprintf("xxx\n"); /* placeholder -- field no longer in use */
328 cprintf("%d\n", config
.c_userpurge
);
329 cprintf("%d\n", config
.c_roompurge
);
330 cprintf("%s\n", config
.c_logpages
);
331 cprintf("%d\n", config
.c_createax
);
332 cprintf("%ld\n", config
.c_maxmsglen
);
333 cprintf("%d\n", config
.c_min_workers
);
334 cprintf("%d\n", config
.c_max_workers
);
335 cprintf("%d\n", config
.c_pop3_port
);
336 cprintf("%d\n", config
.c_smtp_port
);
337 cprintf("%d\n", config
.c_rfc822_strict_from
);
338 cprintf("%d\n", config
.c_aide_zap
);
339 cprintf("%d\n", config
.c_imap_port
);
340 cprintf("%ld\n", config
.c_net_freq
);
341 cprintf("%d\n", config
.c_disable_newu
);
342 cprintf("1\n"); /* niu */
343 cprintf("%d\n", config
.c_purge_hour
);
345 cprintf("%s\n", config
.c_ldap_host
);
346 cprintf("%d\n", config
.c_ldap_port
);
347 cprintf("%s\n", config
.c_ldap_base_dn
);
348 cprintf("%s\n", config
.c_ldap_bind_dn
);
349 cprintf("%s\n", config
.c_ldap_bind_pw
);
357 cprintf("%s\n", config
.c_ip_addr
);
358 cprintf("%d\n", config
.c_msa_port
);
359 cprintf("%d\n", config
.c_imaps_port
);
360 cprintf("%d\n", config
.c_pop3s_port
);
361 cprintf("%d\n", config
.c_smtps_port
);
362 cprintf("%d\n", config
.c_enable_fulltext
);
363 cprintf("%d\n", config
.c_auto_cull
);
364 cprintf("%d\n", config
.c_instant_expunge
);
365 cprintf("%d\n", config
.c_allow_spoofing
);
366 cprintf("%d\n", config
.c_journal_email
);
367 cprintf("%d\n", config
.c_journal_pubmsgs
);
368 cprintf("%s\n", config
.c_journal_dest
);
369 cprintf("%s\n", config
.c_default_cal_zone
);
370 cprintf("%d\n", config
.c_pftcpdict_port
);
371 cprintf("%d\n", config
.c_managesieve_port
);
372 cprintf("%d\n", config
.c_auth_mode
);
373 cprintf("%s\n", config
.c_funambol_host
);
374 cprintf("%d\n", config
.c_funambol_port
);
375 cprintf("%s\n", config
.c_funambol_source
);
376 cprintf("%s\n", config
.c_funambol_auth
);
377 cprintf("%d\n", config
.c_rbl_at_greeting
);
378 cprintf("%s\n", config
.c_master_user
);
379 cprintf("%s\n", config
.c_master_pass
);
380 cprintf("%s\n", config
.c_pager_program
);
381 cprintf("%d\n", config
.c_imap_keep_from
);
382 cprintf("%d\n", config
.c_xmpp_c2s_port
);
383 cprintf("%d\n", config
.c_xmpp_s2s_port
);
384 cprintf("%ld\n", config
.c_pop3_fetch
);
385 cprintf("%ld\n", config
.c_pop3_fastest
);
386 cprintf("%d\n", config
.c_spam_flag_only
);
390 else if (!strcasecmp(cmd
, "SET")) {
392 cprintf("%d Send configuration...\n", SEND_LISTING
);
394 while (client_getln(buf
, sizeof buf
) >= 0 && strcmp(buf
, "000")) {
397 safestrncpy(config
.c_nodename
, buf
,
398 sizeof config
.c_nodename
);
401 safestrncpy(config
.c_fqdn
, buf
,
402 sizeof config
.c_fqdn
);
405 safestrncpy(config
.c_humannode
, buf
,
406 sizeof config
.c_humannode
);
409 safestrncpy(config
.c_phonenum
, buf
,
410 sizeof config
.c_phonenum
);
413 config
.c_creataide
= atoi(buf
);
416 config
.c_sleeping
= atoi(buf
);
419 config
.c_initax
= atoi(buf
);
420 if (config
.c_initax
< 1)
422 if (config
.c_initax
> 6)
426 config
.c_regiscall
= atoi(buf
);
427 if (config
.c_regiscall
!= 0)
428 config
.c_regiscall
= 1;
431 config
.c_twitdetect
= atoi(buf
);
432 if (config
.c_twitdetect
!= 0)
433 config
.c_twitdetect
= 1;
436 safestrncpy(config
.c_twitroom
, buf
,
437 sizeof config
.c_twitroom
);
440 safestrncpy(config
.c_moreprompt
, buf
,
441 sizeof config
.c_moreprompt
);
444 config
.c_restrict
= atoi(buf
);
445 if (config
.c_restrict
!= 0)
446 config
.c_restrict
= 1;
449 safestrncpy(config
.c_site_location
, buf
,
450 sizeof config
.c_site_location
);
453 safestrncpy(config
.c_sysadm
, buf
,
454 sizeof config
.c_sysadm
);
457 config
.c_maxsessions
= atoi(buf
);
458 if (config
.c_maxsessions
< 0)
459 config
.c_maxsessions
= 0;
462 /* placeholder -- field no longer in use */
465 config
.c_userpurge
= atoi(buf
);
468 config
.c_roompurge
= atoi(buf
);
471 safestrncpy(config
.c_logpages
, buf
,
472 sizeof config
.c_logpages
);
475 config
.c_createax
= atoi(buf
);
476 if (config
.c_createax
< 1)
477 config
.c_createax
= 1;
478 if (config
.c_createax
> 6)
479 config
.c_createax
= 6;
482 if (atoi(buf
) >= 8192)
483 config
.c_maxmsglen
= atoi(buf
);
487 config
.c_min_workers
= atoi(buf
);
489 if (atoi(buf
) >= config
.c_min_workers
)
490 config
.c_max_workers
= atoi(buf
);
492 config
.c_pop3_port
= atoi(buf
);
495 config
.c_smtp_port
= atoi(buf
);
498 config
.c_rfc822_strict_from
= atoi(buf
);
501 config
.c_aide_zap
= atoi(buf
);
502 if (config
.c_aide_zap
!= 0)
503 config
.c_aide_zap
= 1;
506 config
.c_imap_port
= atoi(buf
);
509 config
.c_net_freq
= atol(buf
);
512 config
.c_disable_newu
= atoi(buf
);
513 if (config
.c_disable_newu
!= 0)
514 config
.c_disable_newu
= 1;
520 if ((config
.c_purge_hour
>= 0)
521 && (config
.c_purge_hour
<= 23)) {
522 config
.c_purge_hour
= atoi(buf
);
527 safestrncpy(config
.c_ldap_host
, buf
,
528 sizeof config
.c_ldap_host
);
531 config
.c_ldap_port
= atoi(buf
);
534 safestrncpy(config
.c_ldap_base_dn
, buf
,
535 sizeof config
.c_ldap_base_dn
);
538 safestrncpy(config
.c_ldap_bind_dn
, buf
,
539 sizeof config
.c_ldap_bind_dn
);
542 safestrncpy(config
.c_ldap_bind_pw
, buf
,
543 sizeof config
.c_ldap_bind_pw
);
547 safestrncpy(config
.c_ip_addr
, buf
,
548 sizeof config
.c_ip_addr
);
550 config
.c_msa_port
= atoi(buf
);
553 config
.c_imaps_port
= atoi(buf
);
556 config
.c_pop3s_port
= atoi(buf
);
559 config
.c_smtps_port
= atoi(buf
);
562 config
.c_enable_fulltext
= atoi(buf
);
565 config
.c_auto_cull
= atoi(buf
);
568 config
.c_instant_expunge
= atoi(buf
);
571 config
.c_allow_spoofing
= atoi(buf
);
574 config
.c_journal_email
= atoi(buf
);
577 config
.c_journal_pubmsgs
= atoi(buf
);
580 safestrncpy(config
.c_journal_dest
, buf
,
581 sizeof config
.c_journal_dest
);
583 safestrncpy(config
.c_default_cal_zone
, buf
,
584 sizeof config
.c_default_cal_zone
);
587 config
.c_pftcpdict_port
= atoi(buf
);
590 config
.c_managesieve_port
= atoi(buf
);
593 config
.c_auth_mode
= atoi(buf
);
595 safestrncpy(config
.c_funambol_host
, buf
,
596 sizeof config
.c_funambol_host
);
599 config
.c_funambol_port
= atoi(buf
);
602 safestrncpy(config
.c_funambol_source
,
604 sizeof config
.c_funambol_source
);
607 safestrncpy(config
.c_funambol_auth
,
609 sizeof config
.c_funambol_auth
);
612 config
.c_rbl_at_greeting
= atoi(buf
);
615 safestrncpy(config
.c_master_user
, buf
, sizeof config
.c_master_user
);
618 safestrncpy(config
.c_master_pass
, buf
, sizeof config
.c_master_pass
);
621 safestrncpy(config
.c_pager_program
,
623 sizeof config
.c_pager_program
);
626 config
.c_imap_keep_from
= atoi(buf
);
629 config
.c_xmpp_c2s_port
= atoi(buf
);
632 config
.c_xmpp_s2s_port
= atoi(buf
);
635 config
.c_pop3_fetch
= atol(buf
);
638 config
.c_pop3_fastest
= atol(buf
);
641 config
.c_spam_flag_only
= atoi(buf
);
647 snprintf(buf
, sizeof buf
,
648 "The global system configuration has been edited by %s.\n",
650 aide_message(buf
,"Citadel Configuration Manager Message");
652 if (!IsEmptyStr(config
.c_logpages
))
653 create_room(config
.c_logpages
, 3, "", 0, 1, 1, VIEW_BBS
);
655 /* If full text indexing has been disabled, invalidate the
656 * index so it doesn't try to use it later.
658 if (config
.c_enable_fulltext
== 0) {
659 CitControl
.fulltext_wordbreaker
= 0;
664 else if (!strcasecmp(cmd
, "GETSYS")) {
665 extract_token(confname
, argbuf
, 1, '|', sizeof confname
);
666 confptr
= CtdlGetSysConfig(confname
);
667 if (confptr
!= NULL
) {
668 cprintf("%d %s\n", LISTING_FOLLOWS
, confname
);
669 client_write(confptr
, strlen(confptr
));
670 if (confptr
[strlen(confptr
) - 1] != 10)
671 client_write("\n", 1);
675 cprintf("%d No such configuration.\n",
676 ERROR
+ ILLEGAL_VALUE
);
680 else if (!strcasecmp(cmd
, "PUTSYS")) {
681 extract_token(confname
, argbuf
, 1, '|', sizeof confname
);
683 cprintf("%d %s\n", SEND_LISTING
, confname
);
684 confptr
= CtdlReadMessageBody("000", config
.c_maxmsglen
, NULL
, 0, 0);
685 CtdlPutSysConfig(confname
, confptr
);
690 cprintf("%d Illegal option(s) specified.\n",
691 ERROR
+ ILLEGAL_VALUE
);