From f625063cf625f9014aac2b597e8278e9c9aa6768 Mon Sep 17 00:00:00 2001 From: alexhudson Date: Thu, 12 Jul 2007 09:59:43 +0000 Subject: [PATCH] * MDB is now pretty much removed from the store * Merge recent fixes from trunk --- Makefile.am | 7 +- import/log4c/log4c/rc.c | 2 +- include/bongoagent.h | 12 + include/msgapi.h | 6 + mdb-removal_progress.pl | 2 +- po/Makefile.am | 2 + src/agents/alarm/alarm.c | 12 - src/agents/antispam/antispam.c | 11 +- src/agents/antispam/antispam.h | 1 + src/agents/antispam/spamd.c | 50 +-- src/agents/avirus/avirus.c | 75 +--- src/agents/avirus/avirus.h | 3 +- src/agents/connmgr/cmmodules/user/cmuser.c | 1 + src/agents/imap/session.c | 2 +- src/agents/store/calendar.c | 6 +- src/agents/store/calendar.h | 2 + src/agents/store/command.c | 42 +-- src/agents/store/config.c | 154 ++------ src/agents/store/store.c | 7 +- src/agents/store/tests/mkauthhash.c | 57 +-- src/apps/config/Bongo.rules | 15 + src/apps/config/config.c | 122 ++++--- src/apps/config/config.h | 38 +- src/apps/config/config/antispam | 3 + src/apps/config/config/antivirus | 4 + src/apps/config/config/manager | 23 ++ src/apps/manager/manager.c | 6 +- src/apps/setup/bongo-setup.py | 2 +- src/libs/logger/Bongo.rules | 5 + src/libs/logger/logger.c | 10 +- src/libs/logger/logs.conf | 35 ++ src/libs/msgapi/msgapi.c | 33 ++ src/libs/nmap/bongoagent.c | 208 +++++++++-- src/www/Bongo.rules | 118 +++--- src/www/compress.py | 400 +++++++++++++++++++++ src/www/css/layout.css | 9 +- src/www/dragonfly-debug.html | 261 ++++++++++++++ src/www/dragonfly.html | 283 ++------------- src/www/js/Calendar.js | 3 +- src/www/js/CalendarDrag.js | 2 +- src/www/js/Composer.js | 107 ++++-- src/www/js/Dragonfly.js | 1 + src/www/js/Login.js | 4 +- src/www/js/Mail.js | 60 +++- src/www/js/MailConversationView.js | 2 +- src/www/js/Preferences.js | 58 ++- src/www/js/Search.js | 33 +- src/www/js/Util.js | 5 +- 48 files changed, 1497 insertions(+), 807 deletions(-) create mode 100644 src/apps/config/config/antispam create mode 100644 src/apps/config/config/antivirus create mode 100644 src/apps/config/config/manager create mode 100644 src/libs/logger/logs.conf create mode 100755 src/www/compress.py create mode 100644 src/www/dragonfly-debug.html diff --git a/Makefile.am b/Makefile.am index 12806ef..5722968 100644 --- a/Makefile.am +++ b/Makefile.am @@ -71,7 +71,8 @@ install-data-hook:: SUBDIRS = \ $(IMPORT_SUBDIRS) \ - import/log4c + import/log4c \ + po doxygen/html: if test "$(DOXYGEN)" != NO_DOXYGEN; then \ @@ -216,4 +217,8 @@ update-makefiles: @for dir in $(include_subdirs) ; do \ echo " cp $(top_srcdir)/Makefile.am.subdir $(top_srcdir)/$$dir/Makefile.am" ; \ cp "$(top_srcdir)/Makefile.am.subdir" "$(top_srcdir)/$$dir/Makefile.am" || exit 1 ; \ + if test "$$dir" == "po" ; then \ + echo "" >> "$(top_srcdir)/$$dir/Makefile.am" || exit 1 ; \ + echo "distclean:" >> "$(top_srcdir)/$$dir/Makefile.am" || exit 1 ; \ + fi ; \ done diff --git a/import/log4c/log4c/rc.c b/import/log4c/log4c/rc.c index f71186c..cdfeba6 100644 --- a/import/log4c/log4c/rc.c +++ b/import/log4c/log4c/rc.c @@ -121,7 +121,7 @@ static int appender_load(log4c_rc_t* this, sd_domnode_t* anode) if (type) { log4c_appender_set_type(app, log4c_appender_type_get(type->value)); - printf("set to type %s\n", type->value); + // printf("set to type %s\n", type->value); } if (layout) diff --git a/include/bongoagent.h b/include/bongoagent.h index bdc2ebe..a7dc5aa 100644 --- a/include/bongoagent.h +++ b/include/bongoagent.h @@ -90,6 +90,18 @@ struct _BongoAgent { BongoManagee *managee; }; +/* Configuration file reading stuff */ + +typedef struct _BongoConfigItem { + BongoJsonType type; + char *source; + void *destination; +} BongoConfigItem; + +BOOL ReadBongoConfiguration(BongoConfigItem *config, char *filename); +BOOL SetBongoConfigItem(BongoConfigItem *schema, BongoJsonNode *node); +void FreeBongoConfiguration(BongoConfigItem *config); + int BongoAgentInit(BongoAgent *agent, const char *agentName, const char *agentDn, diff --git a/include/msgapi.h b/include/msgapi.h index 386ce41..009a64e 100644 --- a/include/msgapi.h +++ b/include/msgapi.h @@ -35,6 +35,12 @@ EXPORT BOOL MsgAuthVerifyPassword(const char *user, const char *password); EXPORT BOOL MsgAuthSetPassword(const char *user, const char *oldpassword, const char *newpassword); EXPORT BOOL MsgAuthGetUserStore(const char *user, struct sockaddr_in *store); +// Misc. util functions + +EXPORT BOOL MsgSetRecoveryFlag(void); +EXPORT BOOL MsgGetRecoveryFlag(void); +EXPORT BOOL MsgGetServerCredential(char *buffer); + #define MSGSRV_LOCAL_SERVER NULL #define MSGSRV_SELECTED_CONTEXT "." diff --git a/mdb-removal_progress.pl b/mdb-removal_progress.pl index 0f981a6..cb9d8fc 100755 --- a/mdb-removal_progress.pl +++ b/mdb-removal_progress.pl @@ -11,7 +11,7 @@ my %libraries = ('connmgr' => 7, 'management' => 14, 'mdb' => 212, 'mdb-file' => my $search = sub { my ($dir, $thing, $original) = @_; - $current = `grep -r "MDB" src/$dir/* | grep -v \.svn | grep -v matches | wc -l`; + $current = `grep -r "MDB" src/$dir/* | grep -v .svn | grep -v matches | wc -l`; chomp $current; my $percent = (100.0 / $original) * ($original - $current); return sprintf("%12s %3d%% (%3d/%3d)", $thing, $percent, $current, $original); diff --git a/po/Makefile.am b/po/Makefile.am index 8830401..6e4412f 100644 --- a/po/Makefile.am +++ b/po/Makefile.am @@ -15,3 +15,5 @@ all clean install: @cd $(top_builddir) && $(MAKE) $(MFLAGS) $(subdir)/$@ + +distclean: diff --git a/src/agents/alarm/alarm.c b/src/agents/alarm/alarm.c index 7238dac..fc39b56 100644 --- a/src/agents/alarm/alarm.c +++ b/src/agents/alarm/alarm.c @@ -351,16 +351,6 @@ AlarmLoop(void *ignored) XplConsolePrintf(AGENT_NAME ": Shutting down.\r\n"); } - -static BOOL -ReadConfiguration(void) -{ - // Since this agent doesn't read any config for the moment, - // just return true (we don't need/want to depend on MDB). - return TRUE; -} - - static void SignalHandler(int sigtype) { @@ -391,8 +381,6 @@ XplServiceMain(int argc, char *argv[]) return -1; } - ReadConfiguration(); - XplSignalHandler(SignalHandler); StreamioInit(); diff --git a/src/agents/antispam/antispam.c b/src/agents/antispam/antispam.c index 6b13e4f..250761f 100644 --- a/src/agents/antispam/antispam.c +++ b/src/agents/antispam/antispam.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -460,7 +461,7 @@ ProcessConnection(ASpamClient *client) } } - if (!blocked && ASpam.spamd.enabled) { + if (!blocked) { blocked = SpamdCheck(&ASpam.spamd, client, qID, hasFlags, msgFlags, source, senderUserName); } @@ -982,7 +983,9 @@ XplServiceMain(int argc, char *argv[]) SpamdStartup(&(ASpam.spamd)); - if (ASpam.spamd.enabled || ASpam.allow.used || ASpam.disallow.used) { + // TODO: *.used variables seem to be about spam IP sources. This doesn't seem to be + // the right place, really... + // if (ASpam.allow.used || ASpam.disallow.used) { if (QueueSocketInit() < 0) { XplConsolePrintf("bongoantispam: Exiting.\r\n"); @@ -1014,11 +1017,13 @@ XplServiceMain(int argc, char *argv[]) NMAPSetEncryption(ASpam.nmap.ssl.context); ASpam.state = ASPAM_STATE_RUNNING; +#if 0 } else { - XplConsolePrintf("bongoantispam: spamd integration is not enabled and no hosts allowed or disallowed; unloading\r\n"); + XplConsolePrintf("bongoantispam: no hosts allowed or disallowed; unloading\r\n"); ASpam.state = ASPAM_STATE_STOPPING; } +#endif XplStartMainThread(PRODUCT_SHORT_NAME, &id, AntiSpamServer, 8192, NULL, ccode); diff --git a/src/agents/antispam/antispam.h b/src/agents/antispam/antispam.h index 6e510ca..6c6936c 100644 --- a/src/agents/antispam/antispam.h +++ b/src/agents/antispam/antispam.h @@ -69,6 +69,7 @@ typedef struct { typedef struct { AddressPool hosts; + BongoArray *hostlist; BOOL enabled; unsigned long connectionTimeout; } SpamdConfig; diff --git a/src/agents/antispam/spamd.c b/src/agents/antispam/spamd.c index 02ff4a1..4dfc471 100644 --- a/src/agents/antispam/spamd.c +++ b/src/agents/antispam/spamd.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -346,39 +347,34 @@ ParseHost(char *buffer, char **host, unsigned short *port, unsigned long *weight * */ +static BongoConfigItem SpamdHostList = { BONGO_JSON_STRING, NULL, &ASpam.spamd.hostlist }; + +static BongoConfigItem SpamdConfigSchema[] = { + { BONGO_JSON_INT, "o:timeout/i", &ASpam.spamd.connectionTimeout }, + { BONGO_JSON_ARRAY, "o:hosts/a", &SpamdHostList}, + { BONGO_JSON_NULL, NULL, NULL }, +}; + BOOL SpamdReadConfiguration(SpamdConfig *spamd, BongoJsonNode *node) { - BongoJsonResult res; - char *host; const char *tempHost; - unsigned short port; - unsigned long weight; + unsigned int i; memset(spamd, 0, sizeof(SpamdConfig)); - res = BongoJsonJPathGetBool(node, "o:enabled/b", &ASpam.spamd.enabled); - if ((res != BONGO_JSON_OK) || (!ASpam.spamd.enabled)) { - /* nothing is configured or we are disabled */ - return(FALSE); - } /* Set up default spamd options. */ spamd->connectionTimeout = SPAMD_DEFAULT_CONNECTION_TIMEOUT; - ConnAddressPoolStartup(&spamd->hosts, 0, 0); - if (BongoJsonJPathGetInt(node, "o:timeout/i", (int *)(&spamd->connectionTimeout)) != BONGO_JSON_OK) { - spamd->connectionTimeout = SPAMD_DEFAULT_CONNECTION_TIMEOUT; - } + if (!ReadBongoConfiguration(SpamdConfigSchema, "antispam")) + return FALSE; - /* hmm, GetString needs a const char * since it is pointer to memory space that the caller should not modify, - * however ParseHost is going to need a char *. i've got to strdup it and then free it, or re-write - * ParseHost to do it. annoying! */ - if (BongoJsonJPathGetString(node, "o:host/s", &tempHost) == BONGO_JSON_OK) { - char *lHost = MemStrdup(tempHost); - host = SPAMD_DEFAULT_ADDRESS; - port = SPAMD_DEFAULT_PORT; - weight = SPAMD_DEFAULT_WEIGHT; + for (i=0; i < BongoArrayCount(ASpam.spamd.hostlist); i++) { + char *hostitem = &BongoArrayIndex(ASpam.spamd.hostlist, char*, i); + char *lHost = MemStrdup(hostitem); + char *host; + int port, weight; ParseHost(lHost, &host, &port, &weight); ConnAddressPoolAddHost(&ASpam.spamd.hosts, host, port, weight); MemFree(lHost); @@ -391,7 +387,6 @@ SpamdReadConfiguration(SpamdConfig *spamd, BongoJsonNode *node) void SpamdShutdown(SpamdConfig *spamd) { - spamd->enabled = FALSE; ConnAddressPoolShutdown(&(spamd->hosts)); memset(spamd, 0, sizeof(SpamdConfig)); @@ -400,14 +395,7 @@ SpamdShutdown(SpamdConfig *spamd) void SpamdStartup(SpamdConfig *spamd) { - if (spamd->enabled) { - if (spamd->hosts.addressCount == 0) { - ConnAddressPoolAddHost(&(spamd->hosts), SPAMD_DEFAULT_ADDRESS, SPAMD_DEFAULT_PORT, SPAMD_DEFAULT_WEIGHT); - } - - return; + if (spamd->hosts.addressCount == 0) { + ConnAddressPoolAddHost(&(spamd->hosts), SPAMD_DEFAULT_ADDRESS, SPAMD_DEFAULT_PORT, SPAMD_DEFAULT_WEIGHT); } - - SpamdShutdown(spamd); - return; } diff --git a/src/agents/avirus/avirus.c b/src/agents/avirus/avirus.c index 5a51756..a129f0b 100755 --- a/src/agents/avirus/avirus.c +++ b/src/agents/avirus/avirus.c @@ -18,6 +18,7 @@ * may find current contact information at www.novell.com. * * (C) 2007 Patrick Felt + * (C) 2007 Alex Hudson ****************************************************************************/ #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1174,58 +1176,32 @@ AntiVirusServer(void *ignored) return; } +static BongoConfigItem AVirusConfig[] = { + { BONGO_JSON_INT, "o:flags/i", &AVirus.flags }, + { BONGO_JSON_STRING, "o:patterns/s", &AVirus.path.patterns }, + { BONGO_JSON_INT, "o:queue/i", &AVirus.nmap.queue }, + { BONGO_JSON_STRING, "o:host/s", &AVirus.clam.host }, + { BONGO_JSON_INT, "o:port/i", &AVirus.clam.addr.sin_port }, + { BONGO_JSON_NULL, NULL, NULL } +}; + static BOOL ReadConfiguration(void) { unsigned char path[XPL_MAX_PATH + 1]; XplDir *dir; XplDir *dirEntry; + struct hostent *he; - unsigned char *pconfig; - BongoJsonNode *node; - BOOL retcode = TRUE; - BOOL enabled = FALSE; - const char *tmpBuffer; - BongoJsonResult res; - - if (!NMAPReadConfigFile("antivirus", &pconfig)) { - printf("manager: couldn't read config from store\n"); - return FALSE; - } - - if (BongoJsonParseString(pconfig, &node) != BONGO_JSON_OK) { - printf("manager: couldn't parse JSON config\n"); - retcode = FALSE; - goto finish; - } + if (! ReadBongoConfiguration(AVirusConfig, "antivirus")) + return FALSE; AVirus.clam.addr.sin_family = AF_INET; - res = BongoJsonJPathGetBool(node, "o:enabled/b", &enabled); - if ((res != BONGO_JSON_OK) || (!enabled)) { - /* nothing configured or we are disabled */ - return FALSE; - } - - res = BongoJsonJPathGetInt(node, "o:flags/i", &AVirus.flags); - res = BongoJsonJPathGetString(node, "o:patterns/s", &AVirus.path.patterns); - res = BongoJsonJPathGetInt(node, "o:queue/i", (int *)&AVirus.nmap.queue); - res = BongoJsonJPathGetString(node, "o:host/s", &tmpBuffer); - if (res == BONGO_JSON_OK) { - struct hostent *he; - he = gethostbyname(tmpBuffer); - if (he) { - memcpy(&AVirus.clam.addr.sin_addr.s_addr, he->h_addr_list[0], sizeof(AVirus.clam.addr.sin_addr.s_addr)); - } - MemFree(tmpBuffer); - } else { - AVirus.clam.addr.sin_addr.s_addr = inet_addr(CLAMAV_DEFAULT_ADDRESS); - } - res = BongoJsonJPathGetInt(node, "o:port/i", (int *)&AVirus.clam.addr.sin_port); - if (res == BONGO_JSON_OK) { - AVirus.clam.addr.sin_port = htons(AVirus.clam.addr.sin_port); - } else { - AVirus.clam.addr.sin_port = htons(CLAMAV_DEFAULT_PORT); + he = gethostbyname(AVirus.clam.host); + if (he) { + memcpy(&AVirus.clam.addr.sin_addr.s_addr, he->h_addr_list[0], + sizeof(AVirus.clam.addr.sin_addr.s_addr)); } MsgGetWorkDir(AVirus.path.work); @@ -1244,19 +1220,7 @@ ReadConfiguration(void) XplCloseDir(dirEntry); } - -#if 0 - MDBSetValueStructContext(NULL, config); - if (MDBRead(MSGSRV_ROOT, MSGSRV_A_ACL, config) > 0) { - HashCredential(MsgGetServerDN(NULL), config->Value[0], AVirus.nmap.hash); - } - - MDBDestroyValueStruct(config); -#endif - -finish: - BongoJsonNodeFree(node); - return retcode; + return TRUE; } #if defined(NETWARE) || defined(LIBC) || defined(WIN32) @@ -1390,7 +1354,6 @@ XplServiceMain(int argc, char *argv[]) AVirus.handle.directory = NULL; AVirus.handle.logging = NULL; - strcpy(AVirus.path.patterns, "sys:/"); strcpy(AVirus.nmap.address, "127.0.0.1"); XplSafeWrite(AVirus.server.active, 0); diff --git a/src/agents/avirus/avirus.h b/src/agents/avirus/avirus.h index adc3e69..ab6f4ad 100755 --- a/src/agents/avirus/avirus.h +++ b/src/agents/avirus/avirus.h @@ -188,7 +188,7 @@ typedef struct _AVirusGlobals { struct { unsigned char work[XPL_MAX_PATH + 1]; - unsigned char patterns[XPL_MAX_PATH + 1]; + unsigned char *patterns; } path; struct { @@ -214,6 +214,7 @@ typedef struct _AVirusGlobals { } stats; struct { + char *host; struct sockaddr_in addr; } clam; } AVirusGlobals; diff --git a/src/agents/connmgr/cmmodules/user/cmuser.c b/src/agents/connmgr/cmmodules/user/cmuser.c index aa3e7a7..af37576 100644 --- a/src/agents/connmgr/cmmodules/user/cmuser.c +++ b/src/agents/connmgr/cmmodules/user/cmuser.c @@ -212,6 +212,7 @@ Cleanup(void *param) unlink(buffer); } } + XplCloseDir(dir); } for (i = 0; i < (User.config.timeout * 60) && !UserUnloadOk; i++) { diff --git a/src/agents/imap/session.c b/src/agents/imap/session.c index 949de10..af00cbd 100644 --- a/src/agents/imap/session.c +++ b/src/agents/imap/session.c @@ -116,7 +116,7 @@ UserLogin(ImapSession *session, unsigned char **username, unsigned char *passwor ccode = UserStoreInitialize(session, *username); if (ccode == STATUS_CONTINUE) { LoggerEvent(Imap.logHandle, LOGGER_SUBSYSTEM_AUTH, LOGGER_EVENT_LOGIN, LOG_INFO, - 0, session->user.name, NULL, XplHostToLittle(session->client.conn->socketAddress.sin_addr.s_addr), 0, NULL, 0); + 0, *username, NULL, XplHostToLittle(session->client.conn->socketAddress.sin_addr.s_addr), 0, NULL, 0); return(STATUS_CONTINUE); } } diff --git a/src/agents/store/calendar.c b/src/agents/store/calendar.c index 6d8825b..f8e75a9 100644 --- a/src/agents/store/calendar.c +++ b/src/agents/store/calendar.c @@ -146,7 +146,7 @@ static int ParseAlarmJson(BongoJsonObject *json, BongoArray *result, BongoMemStack *memstack) { BongoArray *alarms; - int i; + unsigned int i; AlarmInfo *alarm = NULL; if (BongoJsonObjectGetArray(json, "alarms", &alarms)) { @@ -216,8 +216,8 @@ StoreSetAlarm(StoreClient *client, BongoCalTime end; BongoArray alarms; BongoArray *occurrences = NULL; - int i; - int j; + unsigned int i; + unsigned int j; /* parse the alarm info */ diff --git a/src/agents/store/calendar.h b/src/agents/store/calendar.h index 3cd6924..656e735 100644 --- a/src/agents/store/calendar.h +++ b/src/agents/store/calendar.h @@ -28,6 +28,8 @@ XPL_BEGIN_C_LINKAGE const char * StoreProcessIncomingEvent(StoreClient *client, DStoreDocInfo *info, uint64_t linkGuid); +CCode StoreSetAlarm(StoreClient *client, DStoreDocInfo *docinfo, const char *alarmtext); + XPL_END_C_LINKAGE #endif diff --git a/src/agents/store/command.c b/src/agents/store/command.c index dfd5797..b1e0ceb 100644 --- a/src/agents/store/command.c +++ b/src/agents/store/command.c @@ -26,6 +26,7 @@ #include #include "stored.h" +#include "calendar.h" #include "mail.h" #include "conversations.h" @@ -2147,7 +2148,7 @@ ShowInternalProperty(StoreClient *client, { CCode ccode; BongoArray guidlist; - unsigned i; + unsigned int i; BongoArrayInit(&guidlist, sizeof(uint64_t), 64); @@ -3384,7 +3385,7 @@ StoreCommandFLAG(StoreClient *client, uint64_t guid, uint32_t change, int mode) if (ccode) { return ccode; } - return ConnWriteF(client->conn, "1000 %lu %lu\r\n", info.flags, info.flags); + return ConnWriteF(client->conn, "1000 %u %u\r\n", info.flags, info.flags); case STORE_FLAG_ADD: oldFlags = info.flags; info.flags |= change; @@ -3458,7 +3459,7 @@ finish: IndexClose(index); } - return ConnWriteF(client->conn, "1000 %lu %lu\r\n", oldFlags, info.flags); + return ConnWriteF(client->conn, "1000 %u %u\r\n", oldFlags, info.flags); } @@ -3587,7 +3588,7 @@ StoreCommandMAILINGLISTS(StoreClient *client, char *source) { DStoreStmt *stmt; uint32_t required; - CCode ccode; + CCode ccode = 0; int dcode; GetConversationSourceMask(source, &required); @@ -3631,7 +3632,6 @@ StoreCommandMESSAGES(StoreClient *client, const char *source, const char *query, uint64_t *guids = NULL; char buf[200]; int total; - MaskAndFlagStruct mf = { flagsmask, flags }; uint32_t required; ccode = StoreCheckAuthorizationGuid(client, @@ -3700,7 +3700,7 @@ finish: CCode StoreCommandMFLAG(StoreClient *client, uint32_t change, int mode) { - CCode ccode; + CCode ccode = 0; CollectionLockPool collLocks; WatchEventList events; IndexHandle *index; @@ -3832,7 +3832,7 @@ StoreCommandMFLAG(StoreClient *client, uint32_t change, int mode) goto finish; } - ccode = ConnWriteF(client->conn, "2001 %lu %lu\r\n", oldFlags, info.flags); + ccode = ConnWriteF(client->conn, "2001 %u %u\r\n", oldFlags, info.flags); } if (0 != DStoreCommitTransaction(client->handle)) { @@ -3864,12 +3864,9 @@ CCode StoreCommandMIME(StoreClient *client, uint64_t guid) { -#define XPL_MAX_RFC822_LINE 1000 int ccode = 0; DStoreDocInfo info; - char path[XPL_MAX_PATH + 1]; - char buffer[XPL_MAX_RFC822_LINE]; MimeReport *report = NULL; NLockStruct *lock = NULL; @@ -4372,8 +4369,8 @@ CCode StoreCommandREINDEX(StoreClient *client, uint64_t guid) { IndexHandle *index; - CCode ccode; - int dcode; + CCode ccode = 0; + int dcode = 1; DStoreStmt *stmt = NULL; DStoreDocInfo info; @@ -4387,9 +4384,13 @@ StoreCommandREINDEX(StoreClient *client, uint64_t guid) ccode = ConnWriteStr(client->conn, MSG5005DBLIBERR); goto finish; } - while (stmt && - 1 == (dcode = DStoreInfoStmtStep(client->handle, stmt, &info))) + while (stmt && 1 == dcode) { + dcode = DStoreInfoStmtStep(client->handle, stmt, &info); + if (-1 == dcode) { + ccode = ConnWriteStr(client->conn, MSG5005DBLIBERR); + goto finish; + } if (guid) { /* kludgey */ DStoreStmtEnd(client->handle, stmt); stmt = NULL; @@ -4401,10 +4402,6 @@ StoreCommandREINDEX(StoreClient *client, uint64_t guid) IndexDocument(index, client, &info); } - if (-1 == dcode) { - ccode = ConnWriteStr(client->conn, MSG5005DBLIBERR); - } - ccode = ConnWriteStr(client->conn, MSG1000OK); finish: if (index) { @@ -4426,12 +4423,12 @@ StoreCommandRENAME(StoreClient *client, DStoreDocInfo *collection, CCode ccode = 0; int dcode; char oldfilename[STORE_MAX_PATH+1]; + DStoreStmt *stmt = NULL; DStoreDocInfo newcollection; BongoArray subcolls; BongoArray locks; unsigned int i; int success = 0; - DStoreStmt *stmt; ccode = StoreCheckAuthorizationGuid(client, collection->collection, STORE_PRIV_UNBIND); @@ -5192,7 +5189,7 @@ WriteHelper(StoreClient *client, int propcount) { CCode ccode; - size_t written = 0; + int written = 0; const char *errmsg; int i; @@ -5301,7 +5298,7 @@ StoreCommandMWRITE(StoreClient *client, DStoreDocInfo info; IndexHandle *index = NULL; BongoArray guidlist; - int i; + unsigned int i; BongoArrayInit(&guidlist, sizeof(uint64_t), 64); @@ -5349,8 +5346,7 @@ StoreCommandMWRITE(StoreClient *client, unsigned long flags = 0; int propcount = 0; StorePropInfo props[PROP_ARR_SZ]; - int n; - int status; + unsigned int n; char buffer[CONN_BUFSIZE]; if (-1 == (ccode = ConnWriteStr(client->conn, MSG2054SENDDOCS)) || diff --git a/src/agents/store/config.c b/src/agents/store/config.c index fcbd2dc..f89c6c9 100644 --- a/src/agents/store/config.c +++ b/src/agents/store/config.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -37,12 +36,6 @@ BOOL StoreAgentReadConfiguration(BOOL *recover) { - unsigned long used; - - BOOL result = TRUE; - MDBValueStruct *vs; - MDBValueStruct *stores; - tzset(); StoreAgent.startupTime = time(NULL); @@ -55,134 +48,33 @@ StoreAgentReadConfiguration(BOOL *recover) // this is apparently a hack. Perhaps this should be configurable? StoreAgent.server.maxClients = 1024; - if (StoreAgent.installMode) { - // we want to setup a minimal config, just so the store can bootstrap - strcpy(StoreAgent.store.rootDir, XPL_DEFAULT_MAIL_DIR); - strcpy(StoreAgent.store.systemDir, XPL_DEFAULT_STORE_SYSTEM_DIR); - strcpy(StoreAgent.store.spoolDir, XPL_DEFAULT_SPOOL_DIR); - MsgMakePath(StoreAgent.store.rootDir); - MsgMakePath(StoreAgent.store.systemDir); - MsgMakePath(StoreAgent.store.spoolDir); + // paths etc. now fixed in code - if we want to configure these, we need a new system :) + strcpy(StoreAgent.store.rootDir, XPL_DEFAULT_MAIL_DIR); + strcpy(StoreAgent.store.systemDir, XPL_DEFAULT_STORE_SYSTEM_DIR); + strcpy(StoreAgent.store.spoolDir, XPL_DEFAULT_SPOOL_DIR); + MsgMakePath(StoreAgent.store.rootDir); + MsgMakePath(StoreAgent.store.systemDir); + MsgMakePath(StoreAgent.store.spoolDir); - // which hosts do we trust? - StoreAgent.trustedHosts.count = 2; - StoreAgent.trustedHosts.hosts = MemRealloc(StoreAgent.trustedHosts.hosts, sizeof(unsigned long) * 2); - if (!StoreAgent.trustedHosts.hosts) { - StoreAgent.trustedHosts.count = 0; - } else { - StoreAgent.trustedHosts.hosts[0] = inet_addr("127.0.0.1"); - StoreAgent.trustedHosts.hosts[1] = MsgGetHostIPAddress(); // do we need this address too? - } - - return (TRUE); - } - // otherwise, we continue on to load the full config - - vs = MDBCreateValueStruct(StoreAgent.handle.directory, NULL); - if (vs && MDBRead(MSGSRV_ROOT, MSGSRV_A_ACL, vs)) { - gethostname(StoreAgent.server.host, sizeof(StoreAgent.server.host)); - - HashCredential(MsgGetServerDN(NULL), vs->Value[0], StoreAgent.server.hash); - - MDBFreeValues(vs); - } else { - return(FALSE); - } - - if (recover) { - if (MDBRead(StoreAgent.server.dn, MSGSRV_A_SERVER_STATUS, vs) > 0) { - if (XplStrCaseCmp(vs->Value[0], "Shutdown") != 0) { - *recover = TRUE; - } - } - - MDBFreeValues(vs); - } - - MDBSetValueStructContext(StoreAgent.server.dn, vs); - - /* trusted hosts */ - StoreAgent.trustedHosts.count = - MDBRead(MSGSRV_AGENT_STORE, MSGSRV_A_STORE_TRUSTED_HOSTS, vs); - - StoreAgent.trustedHosts.hosts = MemRealloc(StoreAgent.trustedHosts.hosts, - StoreAgent.trustedHosts.count * sizeof(unsigned long)); + // which hosts do we trust? + StoreAgent.trustedHosts.count = 2; + StoreAgent.trustedHosts.hosts = + MemRealloc(StoreAgent.trustedHosts.hosts, sizeof(unsigned long) * 2); if (!StoreAgent.trustedHosts.hosts) { StoreAgent.trustedHosts.count = 0; - } - if (StoreAgent.trustedHosts.count) { - int count = 0; - -#if defined(NETWARE) || defined(LIBC) - StoreAgent.trustedHosts.hosts[count++] = inet_addr("127.0.0.1"); - StoreAgent.trustedHosts.hosts[count++] = MsgGetHostIPAddress(); -#endif - for (used = 0; used < vs->Used; used++) { - StoreAgent.trustedHosts.hosts[count++] = inet_addr(vs->Value[used]); - } - } - MDBFreeValues(vs); - /* end trusted hosts */ - - if (MDBRead(MSGSRV_AGENT_STORE, MSGSRV_A_MESSAGE_STORE, vs) > 0) { - LoggerEvent(StoreAgent.handle.logging, LOGGER_SUBSYSTEM_CONFIGURATION, LOGGER_EVENT_CONFIGURATION_STRING, LOG_INFO, 0, "MSGSRV_A_MESSAGE_STORE", vs->Value[0], 0, 0, NULL, 0); - - MsgCleanPath(vs->Value[0]); - - strcpy(StoreAgent.store.rootDir, vs->Value[0]); - MsgMakePath(StoreAgent.store.rootDir); - - MDBFreeValues(vs); } else { - result = FALSE; - strcpy(StoreAgent.store.rootDir, XPL_DEFAULT_MAIL_DIR); + StoreAgent.trustedHosts.hosts[0] = inet_addr("127.0.0.1"); + StoreAgent.trustedHosts.hosts[1] = MsgGetHostIPAddress(); // do we need this address too? + } + + gethostname(StoreAgent.server.host, sizeof(StoreAgent.server.host)); + if (!MsgGetServerCredential(StoreAgent.server.hash)) + // can't proceed without the server hash.. + return(FALSE); + + if (recover && MsgGetRecoveryFlag()) { + *recover = TRUE; } - MsgMakePath(StoreAgent.store.rootDir); - - /* Create Store Paths if they don't exist */ - if (MDBReadDN(StoreAgent.server.dn, MSGSRV_A_CONTEXT, vs) > 0) { - stores = MDBCreateValueStruct(StoreAgent.handle.directory, NULL); - if (stores) { - for (used = 0; used < vs->Used; used++) { - if (MDBRead(vs->Value[used], MSGSRV_A_MESSAGE_STORE, stores) > 0) { - MsgCleanPath(stores->Value[0]); - MsgMakePath(stores->Value[0]); - MDBFreeValues(stores); - } - } - - MDBDestroyValueStruct(stores); - } else { - result = FALSE; - } - - MDBFreeValues(vs); - } - - strcpy(StoreAgent.store.systemDir, XPL_DEFAULT_STORE_SYSTEM_DIR); - if (MDBRead(MSGSRV_AGENT_QUEUE, MSGSRV_A_STORE_SYSTEM_DIRECTORY, vs) > 0) { - LoggerEvent(StoreAgent.handle.logging, LOGGER_SUBSYSTEM_CONFIGURATION, LOGGER_EVENT_CONFIGURATION_STRING, LOG_INFO, 0, "MSGSRV_A_STORE_SYSTEM_DIRECTORY", vs->Value[0], 0, 0, NULL, 0); - - MsgCleanPath(vs->Value[0]); - strcpy(StoreAgent.store.systemDir, vs->Value[0]); - MsgMakePath(StoreAgent.store.systemDir); - - MDBFreeValues(vs); - } - - strcpy(StoreAgent.store.spoolDir, XPL_DEFAULT_SPOOL_DIR); - if (MDBRead(MSGSRV_AGENT_QUEUE, MSGSRV_A_SPOOL_DIRECTORY, vs) > 0) { - LoggerEvent(StoreAgent.handle.logging, LOGGER_SUBSYSTEM_CONFIGURATION, LOGGER_EVENT_CONFIGURATION_STRING, LOG_INFO, 0, "MSGSRV_A_SPOOL_DIRECTORY", vs->Value[0], 0, 0, NULL, 0); - - MsgCleanPath(vs->Value[0]); - strcpy(StoreAgent.store.spoolDir, vs->Value[0]); - MsgMakePath(StoreAgent.store.spoolDir); - - MDBFreeValues(vs); - } - - MDBDestroyValueStruct(vs); - - return(result); + return(TRUE); } diff --git a/src/agents/store/store.c b/src/agents/store/store.c index 3fb9bb8..a54e8b2 100644 --- a/src/agents/store/store.c +++ b/src/agents/store/store.c @@ -902,7 +902,6 @@ ImportIncomingMail(StoreClient *client) struct stat sb; IndexHandle *index = NULL; long offset = 0; - int i; CollectionLockPool collLocks; WatchEventList events; @@ -1688,7 +1687,7 @@ CollectionLockPoolInit(StoreClient *client, CollectionLockPool *pool) void CollectionLockPoolDestroy(CollectionLockPool *pool) { - int i; + unsigned int i; for (i = 0; i < pool->colls.len; i++) { colldatum coll = BongoArrayIndex(&pool->colls, colldatum, i); @@ -1705,7 +1704,7 @@ NLockStruct * CollectionLockPoolGet(CollectionLockPool *pool, uint64_t guid) { colldatum coll; - int i; + unsigned int i; for (i = 0; i < pool->colls.len; i++) { colldatum coll = BongoArrayIndex(&pool->colls, colldatum, i); @@ -1901,7 +1900,7 @@ WatchEventListAdd(WatchEventList *events, void WatchEventListFire(WatchEventList *events, StoreClient *client) { - int i; + unsigned int i; for (i = 0; i < events->len; i++) { eventdatum evt = BongoArrayIndex(events, eventdatum, i); diff --git a/src/agents/store/tests/mkauthhash.c b/src/agents/store/tests/mkauthhash.c index d3eb787..35aa95e 100644 --- a/src/agents/store/tests/mkauthhash.c +++ b/src/agents/store/tests/mkauthhash.c @@ -30,60 +30,11 @@ main (int argc, char** argv) { } { unsigned char access[NMAP_HASH_SIZE]; // from libs/nmap/nmap.c - MDBHandle directoryHandle; // ditto - MDBValueStruct *v; - unsigned char message[XPLHASH_MD5_LENGTH]; - xpl_hash_context ctx; - int i; - BOOL ccode; - // Initialize used libraries - if ( !MemoryManagerOpen("mkauthhash.c")) { - XplConsolePrintf("MemoryManagerOpen failed\n"); - return 1; - } else if (debugging) { - XplConsolePrintf("MemoryManagerOpen succeeded\n"); - } - if (!MDBInit()) { - XplConsolePrintf("MDBInit failed\n"); - return 2; - } else if (debugging) { - XplConsolePrintf("MDBInit suceeded\n"); - } - directoryHandle = (MDBHandle) MsgInit(); - if ( !directoryHandle ) { - XplConsolePrintf("MsgInit failed\n"); - return 3; - } else if (debugging) { - XplConsolePrintf("MsgInit succeeded\n"); - } - // compute the contents of the access field - v = MDBCreateValueStruct(directoryHandle, NULL); - if ( !v ) { - XplConsolePrintf("MDBCreateValueStruct failed\n"); - return 4; - } else if (debugging) { - XplConsolePrintf("Successfully created a MDB value struct\n"); - } - if (debugging) { - XplConsolePrintf("Retrieving the acl property:\n" - "\tMSGSRV_ROOT=<%s>\n\tMSGSRV_A_ACL=<%s>\n", MSGSRV_ROOT, MSGSRV_A_ACL); - } - MDBRead(MSGSRV_ROOT, MSGSRV_A_ACL, v); - if ( !v->Used ) { - XplConsolePrintf("Couldn't retrieve the acl property\n"); - return 5; - } else if (debugging) { - XplConsolePrintf("Retrieved the ACL property, %i bytes\n", strlen(v->Value[0]) ); - } - ccode = HashCredential(MsgGetServerDN(NULL), v->Value[0], access); - if (!ccode) { - XplConsolePrintf("HashCredential failed\n"); - return 6; - } else if (debugging) { - XplConsolePrintf("HashCredential result stored in access\n"); - } - MDBDestroyValueStruct(v); + if (!MsgGetServerCredential(access)) { + XplConsolePrintf("HashCredential failed\n"); + return 6; + } // mix access with salt XplHashNew(&ctx, XPLHASH_MD5); diff --git a/src/apps/config/Bongo.rules b/src/apps/config/Bongo.rules index c67bd09..1fa7b28 100644 --- a/src/apps/config/Bongo.rules +++ b/src/apps/config/Bongo.rules @@ -19,6 +19,21 @@ bongo_config_LDADD := \ $(GNUTLS_LIBS) \ $(ALL_LIBS) +conf_defaults = \ + src/apps/config/config/manager \ + src/apps/config/config/antivirus \ + src/apps/config/config/antispam + +dist_noinst_DATA += $(conf_defaults) + +src/apps/config/default.set: $(conf_defaults) + @(cd $(top_srcdir)/src/apps/config && tardir=config && $(am__tar)) > $@ + +confdir = $(pkgdatadir)/conf + +conf_DATA := \ + src/apps/config/default.set + src/apps/config/all: bongo-config src/apps/config/clean: clean src/apps/config/install: diff --git a/src/apps/config/config.c b/src/apps/config/config.c index ca858ae..f547c83 100644 --- a/src/apps/config/config.c +++ b/src/apps/config/config.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "config.h" @@ -79,13 +80,10 @@ SetAdminRights(StoreClient *client, char *document) { } BOOL -PutOrReplaceConfig(StoreClient *client, char *collection, char *filename, char *content) { - int len; +PutOrReplaceConfig(StoreClient *client, char *collection, char *filename, char *content, long len) { CCode ccode; char command[1024]; - len = strlen(content); - snprintf(command, 1000, "INFO %s/%s\r\n", collection, filename); ccode = NMAPSendCommandF(client->conn, command); ccode = NMAPReadAnswer(client->conn, client->buffer, sizeof(client->buffer), TRUE); @@ -94,11 +92,11 @@ PutOrReplaceConfig(StoreClient *client, char *collection, char *filename, char * if (ccode == 1000) { // INFO returned OK, document already exists - snprintf(command, 1000, "REPLACE %s/%s %d\r\n", + snprintf(command, 1000, "REPLACE %s/%s %ld\r\n", collection, filename, len); } else { // INFO errored, so document doesn't exist - snprintf(command, 1000, "WRITE %s %d %d \"F%s\"\r\n", + snprintf(command, 1000, "WRITE %s %d %ld \"F%s\"\r\n", collection, STORE_DOCTYPE_CONFIG, len, filename); } @@ -119,6 +117,75 @@ PutOrReplaceConfig(StoreClient *client, char *collection, char *filename, char * return FALSE; } +BOOL +ImportSystemBackupFile(const StoreClient *client, const char *path) +{ + FILE *config; + char header[513]; + CCode result; + + result = NMAPSimpleCommand(client, "CREATE /config\r\n"); + if ((result==1000) || (result==4226)) { + // collection can't be created and doesn't exist + XplConsolePrintf(_("ERROR: Couldn't create collection\n")); + return FALSE; + } + if (! SetAdminRights(client, "/config")) { + XplConsolePrintf(_("ERROR: Couldn't set acls on /config\n")); + return FALSE; + } + + config = fopen(path, "r"); + if (config == NULL) { + XplConsolePrintf(_("ERROR: Couldn't load default config set\n")); + return FALSE; + } + while(512 == fread(&header, sizeof(char), 512, config)) { + long filesize, blocksize, read; + char str_filesize[13], filename[101]; + char *file; + header[512] = 0; + + memcpy(&filename, &header, 100); + filename[100] = 0; + memcpy(&str_filesize, &header[124], 12); + str_filesize[12] = 0; + filesize = strtol(str_filesize, NULL, 8); + + if (! strncmp(filename, "", 100)) { + // end of tar is _two_ empty blocks... ah well :o> + break; + } + + blocksize = filesize / 512; + if (filesize % 512) blocksize++; + blocksize *= 512; + + if (blocksize > 0 && !strncmp(filename, "config/", 7)) { + char fullpath[110]; + file = MemMalloc((size_t) blocksize); + read = fread(file, sizeof(char), blocksize, config); + if (read != blocksize) { + XplConsolePrintf(" Read error!"); + } + + snprintf(fullpath, 108, "/%s", filename); + if (!PutOrReplaceConfig(client, "/config", + &filename[7], file, filesize)) { + XplConsolePrintf(_("ERROR: Couldn't write\n")); + } else { + if (! SetAdminRights(client, fullpath)) { + XplConsolePrintf(_("ERROR: rigts\n")); + } + } + MemFree(file); + } + } + + fclose(config); + return TRUE; +} + void InitialStoreConfiguration() { char path[XPL_MAX_PATH]; @@ -151,7 +218,6 @@ InitialStoreConfiguration() { exit(1); } else { // parent StoreClient *client; - int result = 0; XplDelay(1000); // FIXME: small hack, wait for store to start. @@ -174,41 +240,15 @@ InitialStoreConfiguration() { XplConsolePrintf(_("ERROR: Couldn't access store\n")); goto nmapcleanup; } - result = NMAPSimpleCommand(client, "CREATE /config\r\n"); - if ((result==1000) || (result==4226)) { - // collection can't be created and doesn't exist - XplConsolePrintf(_("ERROR: Couldn't create collection\n")); - goto nmapcleanup; - } - if (! SetAdminRights(client, "/config")) { - XplConsolePrintf(_("ERROR: Couldn't set acls on /config\n")); - goto nmapcleanup; - } - - XplConsolePrintf(_("Setting default agent configuration...\n")); - if (!PutOrReplaceConfig(client, "/config", "manager", bongo_manager_config)) { - XplConsolePrintf(_("ERROR: couldn't write /config/manager\n")); - } - if (! SetAdminRights(client, "/config/manager")) { - XplConsolePrintf(_("ERROR: Couldn't set acls on /config/manager\n")); - goto nmapcleanup; - } - if (!PutOrReplaceConfig(client, "/config", "antivirus", bongo_avirus_config)) { - XplConsolePrintf(_("ERROR: couldn't write /config/antivirus\n")); - } - if (! SetAdminRights(client, "/config/antivirus")) { - XplConsolePrintf(_("ERROR: Couldn't set acls on /config/antivirus\n")); - goto nmapcleanup; - } - if (!PutOrReplaceConfig(client, "/config", "antispam", bongo_aspam_config)) { - XplConsolePrintf(_("ERROR: couldn't write /config/antispam\n")); - } - if (! SetAdminRights(client, "/config/antispam")) { - XplConsolePrintf(_("ERROR: Couldn't set acls on /config/antispam\n")); - goto nmapcleanup; - } - XplConsolePrintf(_("Complete.\n")); + XplConsolePrintf(_("Setting default agent configuration...\n")); + + snprintf(path, XPL_MAX_PATH, "%s/conf/default.set", XPL_DEFAULT_DATA_DIR); + if (! ImportSystemBackupFile(client, path)) { + XplConsolePrintf(_("ERROR: Couldn't setup default configuration\n")); + } else { + XplConsolePrintf(_("Complete.\n")); + } nmapcleanup: NMAPQuit(client->conn); diff --git a/src/apps/config/config.h b/src/apps/config/config.h index bdd23a7..9d3c16f 100644 --- a/src/apps/config/config.h +++ b/src/apps/config/config.h @@ -28,49 +28,13 @@ void usage(void); void RunAsBongoUser(void); BOOL NMAPSimpleCommand(StoreClient *client, char *command); BOOL SetAdminRights(StoreClient *client, char *document); -BOOL PutOrReplaceConfig(StoreClient *client, char *collection, char *filename, char *content); +BOOL PutOrReplaceConfig(StoreClient *client, char *collection, char *filename, char *content, long len); void InitialStoreConfiguration(void); void GetInteractiveData(char *description, char **data, char *def); BOOL GenerateCryptoData(void); void CheckVersion(void); void TzCache(void); -/* bongo manager config is an object. One key should be 'agents', whose value - * is an array of agent objects. Agent objects can have names, pri (priority) - * and be enabled. Priorities are roughly in terms of dependency and/or which - * order we want things to start in. Low pri == important, high pri == do this - * last. - */ - -static char *bongo_manager_config = -"{ \"version\": 1, \n" -" \"agents\": [ \n" -" { \"name\": \"bongoqueue\", \"pri\": 3, \"enabled\": true },\n" -" { \"name\": \"bongosmtp\", \"pri\": 3, \"enabled\": true },\n" -" { \"name\": \"bongoantispam\", \"pri\": 5, \"enabled\": true },\n" -" { \"name\": \"bongoavirus\", \"pri\": 5, \"enabled\": true },\n" -" { \"name\": \"bongocollector\", \"pri\": 7, \"enabled\": true },\n" -" { \"name\": \"bongomailprox\", \"pri\": 7, \"enabled\": true },\n" -" { \"name\": \"bongoconnmgr\", \"pri\": 2, \"enabled\": true },\n" -" { \"name\": \"bongopluspack\", \"pri\": 5, \"enabled\": true },\n" -" { \"name\": \"bongorules\", \"pri\": 2, \"enabled\": true },\n" -" { \"name\": \"bongoimap\", \"pri\": 10, \"enabled\": true },\n" -" { \"name\": \"bongopop3\", \"pri\": 10, \"enabled\": true },\n" -" { \"name\": \"bongocalcmd\", \"pri\": 7, \"enabled\": true }\n" -" ]\n" -"}\n"; - -static char *bongo_aspam_config = -"{ \"version\": 1, \n" -" \"enabled\": true\n" -"}\n"; - -static char *bongo_avirus_config = -"{ \"version\": 1, \n" -" \"enabled\": true, \n" -" \"flags\": 168\n" -"}\n"; - /* compat with older gnutls */ #ifndef GNUTLS_DIG_SHA1 // older GNUTLS diff --git a/src/apps/config/config/antispam b/src/apps/config/config/antispam new file mode 100644 index 0000000..a65c065 --- /dev/null +++ b/src/apps/config/config/antispam @@ -0,0 +1,3 @@ +{ + "version": 1 +} diff --git a/src/apps/config/config/antivirus b/src/apps/config/config/antivirus new file mode 100644 index 0000000..8e7f2b0 --- /dev/null +++ b/src/apps/config/config/antivirus @@ -0,0 +1,4 @@ +{ + "version": 1, + "flags": 168 +} diff --git a/src/apps/config/config/manager b/src/apps/config/config/manager new file mode 100644 index 0000000..9508bec --- /dev/null +++ b/src/apps/config/config/manager @@ -0,0 +1,23 @@ +/* bongo manager config is an object. One key should be 'agents', whose value + * is an array of agent objects. Agent objects can have names, pri (priority) + * and be enabled. Priorities are roughly in terms of dependency and/or which + * order we want things to start in. Low pri == important, high pri == do this + * last. + */ + +{ "version": 1, + "agents": [ + { "name": "bongoqueue", "pri": 3, "enabled": true }, + { "name": "bongosmtp", "pri": 3, "enabled": true }, + { "name": "bongoantispam", "pri": 5, "enabled": true }, + { "name": "bongoavirus", "pri": 5, "enabled": true }, + { "name": "bongocollector", "pri": 7, "enabled": true }, + { "name": "bongomailprox", "pri": 7, "enabled": true }, + { "name": "bongoconnmgr", "pri": 2, "enabled": true }, + { "name": "bongopluspack", "pri": 5, "enabled": true }, + { "name": "bongorules", "pri": 2, "enabled": true }, + { "name": "bongoimap", "pri": 10, "enabled": true }, + { "name": "bongopop3", "pri": 10, "enabled": true }, + { "name": "bongocalcmd", "pri": 7, "enabled": true } + ] +} diff --git a/src/apps/manager/manager.c b/src/apps/manager/manager.c index 87afe9a..2ffb988 100644 --- a/src/apps/manager/manager.c +++ b/src/apps/manager/manager.c @@ -423,8 +423,7 @@ Lock(BOOL force) exit(1); } - snprintf(pidstr, sizeof(pidstr), "%dl\n", pid); - remaining = sizeof(pidstr); + remaining = snprintf(pidstr, sizeof(pidstr), "%ld\n", pid); ret = 0; written = 0; @@ -601,7 +600,7 @@ StartSlapd(BOOL killExisting) return 1; } } else { - fprintf(stderr, _("bongo-manager: managed-slapd appears to be running as pid %dl\n"), pid); + fprintf(stderr, _("bongo-manager: managed-slapd appears to be running as pid %ld\n"), pid); fprintf(stderr, _("bongo-manager: if this is definitely the bongo slapd, you can run with -e to kill it\n")); return 1; } @@ -638,6 +637,7 @@ StartSlapd(BOOL killExisting) "-f", XPL_DEFAULT_CONF_DIR "/bongo-slapd.conf", "-h", url, "-n", "bongo-slapd", + "-s", "0", NULL); exit(1); diff --git a/src/apps/setup/bongo-setup.py b/src/apps/setup/bongo-setup.py index 7720e44..3ab7ddc 100755 --- a/src/apps/setup/bongo-setup.py +++ b/src/apps/setup/bongo-setup.py @@ -141,7 +141,7 @@ See \"%(bongo_setup)s --help\" for command-line options to further automate the # see if the bongomanager pid is still running try: - pid = int(pid) + pid = long(pid) r = os.kill(pid, 0) raise BongoError("""A possibly stale bongomanager pid file has been found. Either kill process %d (if it is bongomanager) or remove %s""" % (pid, pidfile)) except OSError, e: diff --git a/src/libs/logger/Bongo.rules b/src/libs/logger/Bongo.rules index 3091837..44505ca 100644 --- a/src/libs/logger/Bongo.rules +++ b/src/libs/logger/Bongo.rules @@ -1,6 +1,11 @@ # -*- Makefile -*- lib_LTLIBRARIES += libbongologger.la +logconfdir := $(XPL_DEFAULT_CONF_DIR) + +dist_logconf_DATA := \ + src/libs/logger/logs.conf + libbongologger_la_SOURCES := \ src/libs/logger/bongo.lsc \ src/libs/logger/logger-format.pl \ diff --git a/src/libs/logger/logger.c b/src/libs/logger/logger.c index 165144c..aaa59ac 100644 --- a/src/libs/logger/logger.c +++ b/src/libs/logger/logger.c @@ -45,7 +45,15 @@ LoggerClose(LoggingHandle *handle) EXPORT LoggingHandle * LoggerOpen(const char *name) { - log4c_init(); + char bongo_log_file[XPL_MAX_PATH]; + + if (log4c_init() == -1) { + // log4c couldn't find a file itself, let's default to etc/bongo/logs.conf + snprintf(bongo_log_file, XPL_MAX_PATH, "%s/logs.conf", XPL_DEFAULT_CONF_DIR); + if (log4c_load(bongo_log_file) == -1) { + XplConsolePrintf("ERROR: Unable to find log config %s\n", bongo_log_file); + } + } return (LoggingHandle*)1; } diff --git a/src/libs/logger/logs.conf b/src/libs/logger/logs.conf new file mode 100644 index 0000000..e5207bd --- /dev/null +++ b/src/libs/logger/logs.conf @@ -0,0 +1,35 @@ + + + + + + + 0 + + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/msgapi/msgapi.c b/src/libs/msgapi/msgapi.c index c5006c7..c6a404f 100644 --- a/src/libs/msgapi/msgapi.c +++ b/src/libs/msgapi/msgapi.c @@ -2336,3 +2336,36 @@ MsgInit(void) return((MSGAPIState == LIBRARY_RUNNING) ? MsgGlobal.directoryHandle : NULL); } + +EXPORT BOOL +MsgSetRecoveryFlag(void) +{ + // FIXME: TODO :) + return FALSE; +} + +EXPORT BOOL +MsgGetRecoveryFlag(void) +{ + // FIXME: TODO :) + return FALSE; +} + +EXPORT BOOL +MsgGetServerCredential(char *buffer) +{ + MDBValueStruct *v; + + if (MsgGlobal.directoryHandle) { + v = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL); + if (v) { + MDBRead(MSGSRV_ROOT, MSGSRV_A_ACL, v); + if (v->Used) { + HashCredential(MsgGlobal.server.dn, v->Value[0], buffer); + } + MDBDestroyValueStruct(v); + return TRUE; + } + } + return FALSE; +} diff --git a/src/libs/nmap/bongoagent.c b/src/libs/nmap/bongoagent.c index fa00c47..e13b2a7 100644 --- a/src/libs/nmap/bongoagent.c +++ b/src/libs/nmap/bongoagent.c @@ -18,8 +18,11 @@ * may find current contact information at www.novell.com. * ****************************************************************************/ +// Parts (C) 2007 Alex Hudson. See Bongo Project Licensing. -/* Helpers for queue agent implementation */ +/** \file + * Helpers for Bongo agents. Mainly for queue agents, also contains configuration reading helpers + */ #include @@ -58,31 +61,192 @@ BongoAgentHandleSignal(BongoAgent *agent, return; } -static BOOL -ReadConfiguration(BongoAgent *agent) -{ - MDBValueStruct *config; +BOOL ReadConfiguration(BongoAgent *agent); - config = MDBCreateValueStruct(agent->directoryHandle, - MsgGetServerDN(NULL)); - if (config) { - if (MDBRead(".", MSGSRV_A_OFFICIAL_NAME, config)) { - strcpy(agent->officialName, config->Value[0]); - MDBFreeValues(config); - } else { - agent->officialName[0] = '\0'; - } +BOOL ReadConfiguration(BongoAgent *agent) { + return TRUE; +} - if (MDBRead(agent->name, MSGSRV_A_PORT, config)) { - agent->port = (unsigned short)atol(config->Value[0]); - MDBFreeValues(config); - } +/** + * Free any memory allocated as part of reading the agent's configuration. + * \param config BongoConfigItem array which defines configuration variables + */ +void +FreeBongoConfiguration(BongoConfigItem *config) { + while (config->type != BONGO_JSON_NULL) { + switch (config->type) { + case BONGO_JSON_STRING: + if (config->destination) MemFree(config->destination); + break; + case BONGO_JSON_ARRAY: { + BongoConfigItem *sub = config->destination; + /* if (sub->type == BONGO_JSON_STRING) { + int i; + for (i=0; idestination); i++) { + char *s = &BongoArrayIndex(sub->destination, char*, i); + MemFree(s); + } + }*/ + BongoArrayFree(sub->destination, TRUE); + } + break; + default: + // nothing to do? + break; + } + } +} - MDBDestroyValueStruct(config); - return TRUE; - } +/** + * \internal + * Take an individual BongoConfigItem, and a JSON tree, and try to find the config item + * \param schema pointer to a single BongoConfigItem + * \param node JSON tree we want to look in + * \return Whether or not it was successful + */ - return FALSE; +BOOL +SetBongoConfigItem(BongoConfigItem *schema, BongoJsonNode *node) { + if (!node || node->type != schema->type) { + XplConsolePrintf("config: didn't find data at %s (type: %d, want: %d) \r\n", schema->source, node->type, schema->type); + return FALSE; + } + + switch (node->type) { + case BONGO_JSON_BOOL: { + BOOL *dest = (BOOL *)schema->destination; + *dest = BongoJsonNodeAsBool(node); + } + break; + case BONGO_JSON_DOUBLE: { + double *dest = (double *)schema->destination; + *dest = BongoJsonNodeAsDouble(node); + } + break; + case BONGO_JSON_INT: { + int *dest = (int *)schema->destination; + *dest = BongoJsonNodeAsInt(node); + } + break; + case BONGO_JSON_STRING: { + char **dest = (char **)schema->destination; + *dest = BongoJsonNodeAsString(node); + } + break; + case BONGO_JSON_ARRAY: { + BongoConfigItem *subschema = (BongoConfigItem *)schema->destination; + BongoArray **output = (BongoArray **)subschema->destination; + BongoArray *data, *result = NULL; + int size; + + data = BongoJsonNodeAsArray(node); + size = BongoArrayCount(data); + + switch (subschema->type) { + case BONGO_JSON_BOOL: { + BOOL dest; + int i; + result = BongoArrayNew(sizeof(BOOL), size); + for(i = 0; i < size; i++) { + if (BongoJsonArrayGetBool(data, i, &dest) == BONGO_JSON_OK) { + BongoArrayAppendValue(result, dest); + } else { + return FALSE; + } + } + } + break; + case BONGO_JSON_INT: { + int dest, i; + result = BongoArrayNew(sizeof(int), size); + for(i = 0; i < size; i++) { + if (BongoJsonArrayGetInt(data, i, &dest) == BONGO_JSON_OK) { + BongoArrayAppendValue(result, dest); + } else { + return FALSE; + } + } + } + break; + case BONGO_JSON_STRING: { + const char *dest; + int i; + result = BongoArrayNew(sizeof(char *), size); + for (i=0; idestination as a pointer + to a BongoConfigItem[], and recurse. Makes less sense for + objects, though */ + XplConsolePrintf("config: object type not implemented\r\n"); + break; + default: + XplConsolePrintf("config: unknown type %d!\r\n", node->type); + return FALSE; + break; + } + + return TRUE; +} + +/** + * Read a configuration document from the Bongo Store, and bring information + * from that document into the agent + * \param config BongoConfigItem array which defines configuration variables + * \param filename Filename we wish to read from the store + * \return Whether or not we were successful + */ + +BOOL +ReadBongoConfiguration(BongoConfigItem *config, char *filename) { + unsigned char *pconfig; + BOOL retcode = FALSE; + BongoJsonNode *node = NULL; + + if (! NMAPReadConfigFile(filename, &pconfig)) { + XplConsolePrintf("config: couldn't read config '%s' from store\r\n", filename); + return FALSE; + } + + if (BongoJsonParseString(pconfig, &node) != BONGO_JSON_OK) { + XplConsolePrintf("config: couldn't parse JSON content in '%s'\r\n", filename); + goto finish; + } + + while (config->type != BONGO_JSON_NULL) { + BongoJsonNode *result; + result = BongoJsonJPath(node, config->source); + if (!result) { + XplConsolePrintf("config: JSON tree for schema source %s not found\r\n", config->source); + goto finish; + } + if (!SetBongoConfigItem(config, result)) { + // can't set item + XplConsolePrintf("config: schema source %s not found\r\n", config->source); + } + BongoJsonNodeFree(result); + config++; + } + + retcode = TRUE; + +finish: + if (node) BongoJsonNodeFree(node); + return retcode; } int diff --git a/src/www/Bongo.rules b/src/www/Bongo.rules index d32003f..79cbda2 100644 --- a/src/www/Bongo.rules +++ b/src/www/Bongo.rules @@ -3,6 +3,7 @@ htdocsdir = $(pkgdatadir)/htdocs dist_htdocs_DATA := \ src/www/dragonfly.html \ + src/www/dragonfly-debug.html \ src/www/favicon.ico htl10ndir = $(htdocsdir)/l10n @@ -11,17 +12,27 @@ htl10n_DATA := $(htl10n_jsfiles) cssdir = $(htdocsdir)/css dist_css_DATA := \ - src/www/css/admin.css \ - src/www/css/calendar.css \ - src/www/css/composer.css \ - src/www/css/contacts.css \ - src/www/css/conversation.css \ src/www/css/interpreter.css \ src/www/css/layout.css \ + src/www/css/widgets.css \ src/www/css/login.css \ - src/www/css/print.css \ + src/www/css/composer.css \ + src/www/css/conversation.css \ + src/www/css/contacts.css \ + src/www/css/calendar.css \ src/www/css/summary.css \ - src/www/css/widgets.css + src/www/css/print.css \ + src/www/css/admin.css + +screencssdir = $(cssdir) + +compress_script := $(top_srcdir)/src/www/compress.py + +dist_screencss_DATA = \ + src/www/css/screen.css + +src/www/css/screen.css: $(dist_css_DATA) + $(compress_script) $(dist_css_DATA) --measure -o src/www/css/screen.css -i src/www/css/print.css -i src/www/css/admin.css --no-linebreaks imgdir = $(htdocsdir)/img @@ -208,34 +219,35 @@ dist_img_DATA := \ jsdir = $(htdocsdir)/js +# These *must* be in the order in which they get loaded in the browser dist_js_DATA := \ + src/www/js/Dragonfly.js \ + src/www/js/Format.js \ + src/www/js/Gettext.js \ + src/www/js/Cookie.js \ + src/www/js/Location.js \ + src/www/js/Login.js \ + src/www/js/Util.js \ + src/www/js/Widgets.js \ + src/www/js/ValidatingEntry.js \ + src/www/js/Preferences.js \ src/www/js/AddressBook.js \ - src/www/js/CalendarDrag.js \ - src/www/js/CalendarEditor.js \ - src/www/js/Calendar.js \ - src/www/js/CalendarLayout.js \ - src/www/js/CalendarView.js \ - src/www/js/CalendarWidgets.js \ - src/www/js/Composer.js \ - src/www/js/Cookie.js \ - src/www/js/Dragonfly.js \ - src/www/js/Format.js \ - src/www/js/Gettext.js \ - src/www/js/BongoCalendar.js \ src/www/js/JCal.js \ - src/www/js/Location.js \ - src/www/js/Login.js \ - src/www/js/MailConversationView.js \ - src/www/js/Mail.js \ - src/www/js/MailListView.js \ - src/www/js/MailWidgets.js \ + src/www/js/Calendar.js \ + src/www/js/BongoCalendar.js \ + src/www/js/CalendarEditor.js \ src/www/js/OccurrenceEditor.js \ - src/www/js/Preferences.js \ - src/www/js/Search.js \ + src/www/js/CalendarView.js \ + src/www/js/CalendarLayout.js \ + src/www/js/CalendarDrag.js \ + src/www/js/CalendarWidgets.js \ src/www/js/Summary.js \ - src/www/js/Util.js \ - src/www/js/ValidatingEntry.js \ - src/www/js/Widgets.js \ + src/www/js/Search.js \ + src/www/js/Mail.js \ + src/www/js/MailWidgets.js \ + src/www/js/Composer.js \ + src/www/js/MailConversationView.js \ + src/www/js/MailListView.js \ src/www/js/Browser.js \ src/www/js/BrowserCheck.js @@ -246,37 +258,36 @@ dist_prototype_DATA := \ mochidir = $(jsdir)/lib/MochiKit +# These *must* be in the order in which they get loaded in the browser/MochiKit dist_mochi_DATA := \ + src/www/js/lib/MochiKit/Base.js \ + src/www/js/lib/MochiKit/Iter.js \ + src/www/js/lib/MochiKit/Logging.js \ + src/www/js/lib/MochiKit/DateTime.js \ + src/www/js/lib/MochiKit/Format.js \ src/www/js/lib/MochiKit/Async.js \ - src/www/js/lib/MochiKit/Base.js \ - src/www/js/lib/MochiKit/Color.js \ - src/www/js/lib/MochiKit/DateTime.js \ src/www/js/lib/MochiKit/DOM.js \ - src/www/js/lib/MochiKit/Format.js \ - src/www/js/lib/MochiKit/Iter.js \ - src/www/js/lib/MochiKit/interpreter.js \ - src/www/js/lib/MochiKit/Logging.js \ src/www/js/lib/MochiKit/LoggingPane.js \ - src/www/js/lib/MochiKit/MochiKit.js \ - src/www/js/lib/MochiKit/MochiKit-packed.js \ - src/www/js/lib/MochiKit/MockDOM.js \ - src/www/js/lib/MochiKit/__package__.js \ + src/www/js/lib/MochiKit/Color.js \ src/www/js/lib/MochiKit/Signal.js \ - src/www/js/lib/MochiKit/SimpleTest.js \ - src/www/js/lib/MochiKit/Test.js \ - src/www/js/lib/MochiKit/TestRunner.js \ - src/www/js/lib/MochiKit/Visual.js + src/www/js/lib/MochiKit/Visual.js \ + src/www/js/lib/MochiKit/MochiKit.js \ + src/www/js/lib/MochiKit/interpreter.js scriptaculousdir = $(jsdir)/lib/script.aculo.us +# Same as with above JS. dist_scriptaculous_DATA := \ - src/www/js/lib/script.aculo.us/builder.js \ - src/www/js/lib/script.aculo.us/controls.js \ - src/www/js/lib/script.aculo.us/dragdrop.js \ - src/www/js/lib/script.aculo.us/effects.js \ - src/www/js/lib/script.aculo.us/scriptaculous.js \ - src/www/js/lib/script.aculo.us/slider.js \ - src/www/js/lib/script.aculo.us/unittest.js + src/www/js/lib/script.aculo.us/effects.js \ + src/www/js/lib/script.aculo.us/controls.js + +finaljsdir = $(jsdir) + +dist_finaljs_DATA = \ + src/www/js/final.js + +src/www/js/final.js: $(dist_js_DATA) $(dist_prototype_DATA) $(dist_scriptaculous_DATA) $(dist_mochi_DATA) + $(compress_script) $(dist_prototype_DATA) $(dist_scriptaculous_DATA) $(dist_mochi_DATA) $(dist_js_DATA) -o src/www/js/final.js --measure --type js install-data-local:: install-dist_htdocsDATA ln -sf dragonfly.html "$(DESTDIR)$(htdocsdir)/index.html" @@ -362,7 +373,8 @@ sbin_SCRIPTS += \ src/www/bongo-standalone dist_noinst_SCRIPTS += \ - src/www/l10n/props2json + src/www/l10n/props2json \ + src/www/compress.py templatesdir = $(pkgdatadir)/templates diff --git a/src/www/compress.py b/src/www/compress.py new file mode 100755 index 0000000..b30546d --- /dev/null +++ b/src/www/compress.py @@ -0,0 +1,400 @@ +#!/usr/bin/env python +# +# compress.py +# Compresses Javascript/CSS (what else do you think it does?). + +import re, sys, os, traceback +from optparse import OptionParser +from time import time +from StringIO import StringIO + +# The following code is original from jsmin by Douglas Crockford, it was translated to +# Python by Baruch Even. The following code had the following copyright and +# license. +# +# /* jsmin.c +# 2007-05-22 +# +# Copyright (c) 2002 Douglas Crockford (www.crockford.com) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# The Software shall be used for Good, not Evil. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# */ + +def jsmin(js): + ins = StringIO(js) + outs = StringIO() + JavascriptMinify().minify(ins, outs) + str = outs.getvalue() + if len(str) > 0 and str[0] == '\n': + str = str[1:] + return str + +def isAlphanum(c): + """return true if the character is a letter, digit, underscore, + dollar sign, or non-ASCII character. + """ + return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or + (c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126)); + +class UnterminatedComment(Exception): + pass + +class UnterminatedStringLiteral(Exception): + pass + +class UnterminatedRegularExpression(Exception): + pass + +class JavascriptMinify(object): + + def _outA(self): + self.outstream.write(self.theA) + def _outB(self): + self.outstream.write(self.theB) + + def _get(self): + """return the next character from stdin. Watch out for lookahead. If + the character is a control character, translate it to a space or + linefeed. + """ + c = self.theLookahead + self.theLookahead = None + if c == None: + c = self.instream.read(1) + if c >= ' ' or c == '\n': + return c + if c == '': # EOF + return '\000' + if c == '\r': + return '\n' + return ' ' + + def _peek(self): + self.theLookahead = self._get() + return self.theLookahead + + def _next(self): + """get the next character, excluding comments. peek() is used to see + if a '/' is followed by a '/' or '*'. + """ + c = self._get() + if c == '/': + p = self._peek() + if p == '/': + c = self._get() + while c > '\n': + c = self._get() + return c + if p == '*': + c = self._get() + while 1: + c = self._get() + if c == '*': + if self._peek() == '/': + self._get() + return ' ' + if c == '\000': + raise UnterminatedComment() + + return c + + def _action(self, action): + """do something! What you do is determined by the argument: + 1 Output A. Copy B to A. Get the next B. + 2 Copy B to A. Get the next B. (Delete A). + 3 Get the next B. (Delete B). + action treats a string as a single character. Wow! + action recognizes a regular expression if it is preceded by ( or , or =. + """ + if action <= 1: + self._outA() + + if action <= 2: + self.theA = self.theB + if self.theA == "'" or self.theA == '"': + while 1: + self._outA() + self.theA = self._get() + if self.theA == self.theB: + break + if self.theA <= '\n': + raise UnterminatedStringLiteral() + if self.theA == '\\': + self._outA() + self.theA = self._get() + + + if action <= 3: + self.theB = self._next() + if self.theB == '/' and (self.theA == '(' or self.theA == ',' or + self.theA == '=' or self.theA == ':' or + self.theA == '[' or self.theA == '?' or + self.theA == '!' or self.theA == '&' or + self.theA == '|' or self.theA == ';' or + self.theA == '{' or self.theA == '}' or + self.theA == '\n'): + self._outA() + self._outB() + while 1: + self.theA = self._get() + if self.theA == '/': + break + elif self.theA == '\\': + self._outA() + self.theA = self._get() + elif self.theA <= '\n': + raise UnterminatedRegularExpression() + self._outA() + self.theB = self._next() + + + def _jsmin(self): + """Copy the input to the output, deleting the characters which are + insignificant to JavaScript. Comments will be removed. Tabs will be + replaced with spaces. Carriage returns will be replaced with linefeeds. + Most spaces and linefeeds will be removed. + """ + self.theA = '\n' + self._action(3) + + while self.theA != '\000': + if self.theA == ' ': + if isAlphanum(self.theB): + self._action(1) + else: + self._action(2) + elif self.theA == '\n': + if self.theB in ['{', '[', '(', '+', '-']: + self._action(1) + elif self.theB == ' ': + self._action(3) + else: + if isAlphanum(self.theB): + self._action(1) + else: + self._action(2) + else: + if self.theB == ' ': + if isAlphanum(self.theA): + self._action(1) + else: + self._action(3) + elif self.theB == '\n': + if self.theA in ['}', ']', ')', '+', '-', '"', '\'']: + self._action(1) + else: + if isAlphanum(self.theA): + self._action(1) + else: + self._action(3) + else: + self._action(1) + + def minify(self, instream, outstream): + self.instream = instream + self.outstream = outstream + self.theA = '\n' + self.theB = None + self.theLookahead = None + + self._jsmin() + self.instream.close() + +# The following code is (c) 2007 Alexander Hixon +# See COPYING for more details. + +if __name__ == "__main__": + desc = "Compresses Javascript and CSS files, so that web applications can have lower download times and save bandwidth. This tool mainly removes unnecessary whitespace and removes comments; it does not modify quoted strings, regular expression literals or variable names." + parser = OptionParser(usage="%prog [options] inputfile ...", version="%prog 1.0", description=desc); + parser.add_option('-n', '--no-linebreaks', + dest='linebreaks', + action='store_true', + default=False, + help="remove all line breaks in the resulting file (not valid for Javascript) [default: %default]") + parser.add_option('-q', '--quiet', + dest='quiet', + action='store_true', + default=False, + help="be vewwy quiet!") + parser.add_option('-m', '--measure', + dest='measure', + default=False, + action='store_true', + help="print compression statistics") + + parser.add_option('-t', '--type', + dest='filetype', + default='autodetect', + help="type of file ('autodetect', 'js' and 'css' are all valid).") + parser.add_option('-o', '--output', + dest='output', + help="file to save resulting compressed file(s) to") + parser.add_option('-i', '--ignore', + dest='ignore', + action='append', + help="ignore a certain filename") + parser.add_option('--no-compression', + dest='nocompression', + default=False, + help="don't compress anything") + + (options, args) = parser.parse_args() + + # Make sure we don't append to an alreaady existing output (that's stupid) + if options.output and os.path.exists(options.output): + if options.quiet: + print "** Warning: output file already exists - overwriting." + os.remove(options.output) + + # Setup our counters for stats later + lengthBefore = 0 + lengthAfter = 0 + + # Check for inputs + if not len(args) > 0: + if not options.quiet: + print "Error: no input files specified." + sys.exit(1) + + # Make sure the user doesn't want to measure multiple inputs and outputs; + # we can only handle measuring a single output, with either single or many inputs. + if options.measure: + if len(args) > 1 and not options.output: + if not options.quiet: + print "Error: unable to measure multiple input files and output files." + print " Please specify a single output, or drop the --measure argument." + sys.exit(1) + + # Filetype auto-detection! + ftype = options.filetype + if ftype == 'autodetect': + # Work out the filetype based on the extension of first file + ext = "" + try: + ext = os.path.splitext(args[0])[1] + except: + # Fail if we can't get the extention + if not options.quiet: + print "Error: Could not determine filetype automatically. Please specify if using" + print " the --type argument." + sys.exit(1) + + if ext == '.js': + ftype = 'js' + elif ext == '.css': + ftype = 'css' + else: + # Tell the user off for trying something that doesn't look valid. + print "Error: unsupported filetype or incorrectly autodetected." + print " If you're sure that kind of file is supported, force the filetype with" + print " the --type argument." + sys.exit(1) + + # If we get here, all is OK! + + # Find out when we start (for timer) + start = time() + + # Loop through each input + for arg in args: + fn = arg + if not options.quiet: + print "Compressing " + fn + "..." + try: + if not os.path.exists(fn): + if not options.quiet: + print "** Warning: file " + fn + " does not exist." + continue + + if options.ignore and options.ignore.count(fn) > 0: + if not options.quiet: + print "** Warning: skipping file " + fn + "." + continue + + f = open(fn) + destfn = fn + '.compressed' + writemode = 'w' + # Set mode to 'write' if no output was specified (many in-many out), or + # append if we were given an output (many in-single out). + if options.output: + destfn = options.output + writemode = 'a' + r = open(destfn, writemode) + try: + # Type-based operations + if options.nocompression: + # If the user doesn't actually /want/ to compress anything, just cat the files together. + r.write(f.read()) + elif ftype == "js" or ftype == "javascript": + c = JavascriptMinify() + c.minify(f, r) + + # Tell use they can't remove line breaks - it borks some JS files! + if options.linebreaks and not options.quiet: + print "** Warning: --nolinebreaks is not supported on Javascript files." + elif ftype == "css" or ftype == "stylesheet": + css = f.read() + css = re.sub(r'/[*]([^*]|(\*[^/]))*[*]/', '', css) # Strip C-style comments + css = re.sub(r'\s+', ' ', css) # compress whitespace + css = css.replace('\t', '') + if options.linebreaks: + css = css.replace('\n', '') + + r.write(css) + else: + if not options.quiet: + print "Error: unsupported file type." + break + finally: + # Close streams. + f.close() + r.close() + + # Update counters. + lengthBefore += float(os.path.getsize(fn)) + if not options.output: + lengthAfter += float(os.path.getsize(destfn)) + else: + lengthAfter = float(os.path.getsize(destfn)) + except Exception, ex: + if not options.quiet: + print "** Warning: failed to compress file " + fn + "." + print "Exception: " + str(ex) + + # And stop counting. + stop = time() + + if not options.quiet: + if options.measure: + # Print stats. + squeezeRate = int(100*(1-(lengthAfter/lengthBefore))) + kbsize = round((lengthBefore - lengthAfter) / 1024, 2) + timetook = stop - start + print + print " Size before compression : " + str(round(lengthBefore / 1024, 2)) + " KB" + print " Size after compression : " + str(round(lengthAfter / 1024, 2)) + " KB" + print " Percentage of savings : " + str(squeezeRate) + "%" + print " Size saved : " + str(kbsize) + " KB" + print " Compressed in : %3.3f" % timetook + " sec" + print " Compression rate : " + str(round(kbsize / timetook, 2)) + " KB/sec" + + print + print "Complete." diff --git a/src/www/css/layout.css b/src/www/css/layout.css index c02cded..92f2e95 100644 --- a/src/www/css/layout.css +++ b/src/www/css/layout.css @@ -12,7 +12,7 @@ form p { margin: 0.5em 0; } -input, textarea, select, option, table { +input, select, option, table { font-family: inherit; font-size: inherit; /* we probably shouldn't inherit the color without inheriting @@ -887,13 +887,16 @@ body.eng-msie #page-frame { .right { float: right; } /*** Forms style ***/ -input, -textarea { +input { font-family: inherit; font-size: inherit; /* we probably shouldn't inherit the color without inheriting background? */ /* color: inherit; */ +} + +input, +textarea { padding: 1px; } input[type="text"], diff --git a/src/www/dragonfly-debug.html b/src/www/dragonfly-debug.html new file mode 100644 index 0000000..fc9323b --- /dev/null +++ b/src/www/dragonfly-debug.html @@ -0,0 +1,261 @@ + + + + + + + Bongo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/src/www/dragonfly.html b/src/www/dragonfly.html index 15e349c..dc8e21e 100644 --- a/src/www/dragonfly.html +++ b/src/www/dragonfly.html @@ -1,266 +1,31 @@ - - - - - - - Bongo - - - - - -