diff --git a/configure.ac b/configure.ac index dd618f3..1f9da50 100644 --- a/configure.ac +++ b/configure.ac @@ -682,6 +682,7 @@ src/libs/nmap/Makefile src/libs/python/Makefile src/libs/python/bongo-python-wrapper src/libs/python/libbongo/Makefile +src/libs/python/bongo/Makefile src/libs/python/bongo/Xpl.py src/libs/bongoutil/Makefile src/libs/bongoutil/tests/Makefile diff --git a/import/log4c/log4c.h b/import/log4c/log4c.h index f7fb45d..068902e 100644 --- a/import/log4c/log4c.h +++ b/import/log4c/log4c.h @@ -62,8 +62,14 @@ #define LOGIP(X) inet_ntoa(X.sin_addr) +#define LogFailure(message) Log(LOG_ERROR, "Internal Failure (%s:%d) " message, __FILE__, __LINE__) +#define LogFailureF(message, ...) Log(LOG_ERROR, "Internal Failure (%s:%d) " message, __FILE__, __LINE__, __VA_ARGS__) +#define LogAssert(test, message) if (!(test)) { Log(LOG_ERROR, "Internal Failure (%s:%d) " message, __FILE__, __LINE__); } +#define LogAssertF(test, message, ...) if(!(test)) { Log(LOG_ERROR, "Assert:%s:%d " message, __FILE__, __LINE__, __VA_ARGS__); } + #define Log(...) LogMsg(LOGGERNAME, 0, __VA_ARGS__) #define LogWithID(...) LogMsg(LOGGERNAME, __VA_ARGS__) +#define LogStart() LoggerOpen(LOGGERNAME); #define LogStartup() log4c_init() #define LogShutdown() log4c_fini() diff --git a/m4/acx_clucene.m4 b/m4/acx_clucene.m4 index 3850f2f..224cbef 100644 --- a/m4/acx_clucene.m4 +++ b/m4/acx_clucene.m4 @@ -70,7 +70,7 @@ AC_LANG(C++) fi CLUCENE_BONGO_API=`echo "$clucene_ver" | $AWK -F. '{ - if ($ 1 > 0 || $ 2 > 9 || ($ 2 == 9 && $ 3 > 18)) { + if ($ 1 > 0 || $ 2 > 9 || ($ 2 == 9 && $ 3 >= 17)) { print 2; } else { print 1; diff --git a/src/agents/imap/imapd.c b/src/agents/imap/imapd.c index 223857f..fb9ee38 100644 --- a/src/agents/imap/imapd.c +++ b/src/agents/imap/imapd.c @@ -103,25 +103,6 @@ static ProtocolCommand ImapProtocolCommands[] = { void *IMAPConnectionPool = NULL; -/* Management Client Declarations */ -BOOL ReadIMAPVariable(unsigned int Variable, unsigned char *Data, size_t *DataLength); -BOOL WriteIMAPVariable(unsigned int Variable, unsigned char *Data, size_t DataLength); - -ManagementVariables IMAPManagementVariables[] = { - /* 0 #define PRODUCT_VERSION */ { DMCMV_REVISIONS, DMCMV_REVISIONS_HELP, ReadIMAPVariable, NULL }, - /* 1 unsigned long Imap.session.threads.max */ { DMCMV_MAX_CONNECTION_COUNT, DMCMV_MAX_CONNECTION_COUNT_HELP, ReadIMAPVariable, WriteIMAPVariable }, - /* 2 XplAtomic IMAPServerThreads */ { DMCMV_SERVER_THREAD_COUNT, DMCMV_SERVER_THREAD_COUNT_HELP, ReadIMAPVariable, NULL }, - /* 3 XplAtomic Imap.session.threads.inUse */ { DMCMV_CONNECTION_COUNT, DMCMV_CONNECTION_COUNT_HELP, ReadIMAPVariable, NULL }, - /* 4 XplAtomic Imap.session.threads.idle */ { DMCMV_IDLE_CONNECTION_COUNT, DMCMV_IDLE_CONNECTION_COUNT_HELP, ReadIMAPVariable, NULL }, - /* 5 BOOL Imap.command.capability.acl.enabled */ { IMAPMV_ACL_ENABLED, IMAPMV_ACL_ENABLED_HELP, ReadIMAPVariable, NULL }, - /* 6 BOOL Imap.server.disabled */ { DMCMV_RECEIVER_DISABLED, DMCMV_RECEIVER_DISABLED_HELP, ReadIMAPVariable, WriteIMAPVariable }, - /* 7 unsigned char Imap.server.hostname[256] */ { DMCMV_HOSTNAME, DMCMV_HOSTNAME_HELP, ReadIMAPVariable, NULL }, - /* 8 unsigned char Imap.server.postmaster[MAXEMAILNAMESIZE + 1] */ { DMCMV_POSTMASTER, DMCMV_POSTMASTER_HELP, ReadIMAPVariable, NULL }, - /* 9 XplAtomic Imap.session.served */ { DMCMV_TOTAL_CONNECTIONS, DMCMV_TOTAL_CONNECTIONS_HELP, ReadIMAPVariable, WriteIMAPVariable }, - /* 10 XplAtomic Imap.session.badPassword */ { DMCMV_BAD_PASSWORD_COUNT, DMCMV_BAD_PASSWORD_COUNT_HELP, ReadIMAPVariable, WriteIMAPVariable }, - /* 11 unsigned char DMC Version */ { DMCMV_VERSION, DMCMV_VERSION_HELP, ReadIMAPVariable, NULL }, -}; - static void FreeReturnValueIndex(unsigned long *index) { @@ -214,389 +195,6 @@ IMAPShutdown(unsigned char *Arguments, unsigned char **Response, BOOL *CloseConn return(FALSE); } -static BOOL -IMAPDMCCommandHelp(unsigned char *Arguments, unsigned char **Response, BOOL *CloseConnection) -{ - BOOL responded = FALSE; - - if (Response) { - if (Arguments) { - switch(toupper(Arguments[0])) { - case 'M': { - if (XplStrNCaseCmp(Arguments, DMCMC_DUMP_MEMORY_USAGE, sizeof(DMCMC_DUMP_MEMORY_USAGE) - 1) == 0) { - if ((*Response = MemStrdup(DMCMC_DUMP_MEMORY_USAGE_HELP)) != NULL) { - responded = TRUE; - } - - break; - } - } - - case 'C': { - if (XplStrNCaseCmp(Arguments, DMCMC_CONN_TRACE_USAGE, sizeof(DMCMC_CONN_TRACE_USAGE) - 1) == 0) { - if ((*Response = MemStrdup(DMCMC_CONN_TRACE_USAGE_HELP)) != NULL) { - responded = TRUE; - } - - break; - } - } - - case 'S': { - if (XplStrNCaseCmp(Arguments, DMCMC_STATS, sizeof(DMCMC_STATS) - 1) == 0) { - if ((*Response = MemStrdup(DMCMC_STATS_HELP)) != NULL) { - responded = TRUE; - } - - break; - } else if (XplStrNCaseCmp(Arguments, DMCMC_SHUTDOWN, sizeof(DMCMC_SHUTDOWN) - 1) == 0) { - if ((*Response = MemStrdup(DMCMC_SHUTDOWN_HELP)) != NULL) { - responded = TRUE; - } - - break; - } - } - - default: { - break; - } - } - } else if ((*Response = MemStrdup(DMCMC_HELP_HELP)) != NULL) { - responded = TRUE; - } - - if (responded || ((*Response = MemStrdup(DMCMC_UNKOWN_COMMAND)) != NULL)) { - return(TRUE); - } - } - - return(FALSE); -} - -static BOOL -SendIMAPStatistics(unsigned char *Arguments, unsigned char **Response, BOOL *CloseConnection) -{ - MemStatistics poolStats; - - if (!Arguments && Response) { - memset(&poolStats, 0, sizeof(MemStatistics)); - - *Response = MemMalloc(sizeof(PRODUCT_NAME) /* Long Name */ - + sizeof(PRODUCT_SHORT_NAME) /* Short Name */ - + 10 /* PRODUCT_MAJOR_VERSION */ - + 10 /* PRODUCT_MINOR_VERSION */ - + 10 /* PRODUCT_LETTER_VERSION */ - + 10 /* Connection Pool Alloc Count */ - + 10 /* Connection Pool Memory Usage */ - + 10 /* Connection Pool Pitches */ - + 10 /* Connection Pool Strikes */ - + 10 /* DMCMV_SERVER_THREAD_COUNT */ - + 10 /* DMCMV_CONNECTION_COUNT */ - + 10 /* DMCMV_IDLE_CONNECTION_COUNT */ - + 10 /* DMCMV_MAX_CONNECTION_COUNT */ - + 10 /* DMCMV_TOTAL_CONNECTIONS */ - + 10 /* DMCMV_BAD_PASSWORD_COUNT */ - + 28); /* Formatting */ - - MemPrivatePoolStatistics(IMAPConnectionPool, &poolStats); - - if (*Response) { - sprintf(*Response, "%s (%s: v%d.%d.%d)\r\n%lu:%lu:%lu:%lu:%d:%d:%d:%lu:%d:%d\r\n", - PRODUCT_NAME, - PRODUCT_SHORT_NAME, - PRODUCT_MAJOR_VERSION, - PRODUCT_MINOR_VERSION, - PRODUCT_LETTER_VERSION, - poolStats.totalAlloc.count, - poolStats.totalAlloc.size, - poolStats.pitches, - poolStats.strikes, - XplSafeRead(Imap.server.active), - XplSafeRead(Imap.session.threads.inUse), - XplSafeRead(Imap.session.threads.idle), - Imap.session.threads.max, - XplSafeRead(Imap.session.served), - XplSafeRead(Imap.session.badPassword)); - - return(TRUE); - } - - if ((*Response = MemStrdup("Out of memory.\r\n")) != NULL) { - return(TRUE); - } - } else if ((Arguments) && ((*Response = MemStrdup("Arguments not allowed.\r\n")) != NULL)) { - return(TRUE); - } - - return(FALSE); -} - -ManagementCommands IMAPManagementCommands[] = { - /* 0 HELP[ ] */ { DMCMC_HELP, IMAPDMCCommandHelp }, - /* 1 SHUTDOWN */ { DMCMC_SHUTDOWN, IMAPShutdown }, - /* 2 STATS */ { DMCMC_STATS, SendIMAPStatistics }, - /* 3 MEMORY */ { DMCMC_DUMP_MEMORY_USAGE, ManagementMemoryStats }, - /* 4 CONNTRACEFLAGS */ { DMCMC_CONN_TRACE_USAGE, ManagementConnTrace }, -}; - -/* Management Client Read Function */ -BOOL ReadIMAPVariable(unsigned int Variable, unsigned char *Data, size_t *DataLength) -{ - unsigned long count; - unsigned char *ptr; - - switch (Variable) { - case 0: { /* #define PRODUCT_VERSION */ - unsigned char version[30]; - - PVCSRevisionToVersion(PRODUCT_VERSION, version); - count = strlen(version) + 11; - - if (Data && (*DataLength > count)) { - ptr = Data; - - PVCSRevisionToVersion(PRODUCT_VERSION, version); - ptr += sprintf(ptr, "imapd.c: %s\r\n", version); - - *DataLength = ptr - Data; - } else { - *DataLength = count; - } - - break; - } - - case 1: { /* unsigned long Imap.session.threads.max */ - if (Data && (*DataLength > 12)) { - sprintf(Data, "%010lu\r\n", Imap.session.threads.max); - } - - *DataLength = 12; - break; - } - - case 2: { /* XplAtomic IMAPServerThreads */ - if (Data && (*DataLength > 12)) { - sprintf(Data, "%010lu\r\n", (long unsigned int)XplSafeRead(Imap.server.active)); - } - - *DataLength = 12; - break; - } - - case 3: { /* XplAtomic Imap.session.threads.inUse */ - if (Data && (*DataLength > 12)) { - sprintf(Data, "%010lu\r\n", (long unsigned int)XplSafeRead(Imap.session.threads.inUse)); - } - - *DataLength = 12; - break; - } - - case 4: { /* XplAtomic Imap.session.threads.idle */ - if (Data && (*DataLength > 12)) { - sprintf(Data, "%010lu\r\n", (long unsigned int)XplSafeRead(Imap.session.threads.idle)); - } - - *DataLength = 12; - break; - } - - case 5: { /* BOOL Imap.command.capability.acl.enabled */ - if (Imap.command.capability.acl.enabled == FALSE) { - ptr = "FALSE\r\n"; - count = 7; - } else { - ptr = "TRUE\r\n"; - count = 6; - } - - if (Data && (*DataLength > count)) { - strcpy(Data, ptr); - } - - *DataLength = count; - break; - } - - case 6: { /* BOOL Imap.server.disabled */ - if (Imap.server.disabled == FALSE) { - ptr = "FALSE\r\n"; - count = 7; - } else { - ptr = "TRUE\r\n"; - count = 6; - } - - if (Data && (*DataLength > count)) { - strcpy(Data, ptr); - } - - *DataLength = count; - break; - } - - case 7: { /* unsigned char Imap.server.hostname[256] */ - count = strlen(Imap.server.hostname) + 2; - if (Data && (*DataLength > count)) { - sprintf(Data, "%s\r\n", Imap.server.hostname); - } - - *DataLength = count; - break; - } - - case 8: { /* unsigned char Imap.server.postmaster[MAXEMAILNAMESIZE + 1] */ - count = strlen(Imap.server.postmaster) + 2; - if (Data && (*DataLength > count)) { - sprintf(Data, "%s\r\n", Imap.server.postmaster); - } - - *DataLength = count; - break; - } - - case 9: { /* XplAtomic Imap.session.served */ - if (Data && (*DataLength > 12)) { - sprintf(Data, "%010lu\r\n", (long unsigned int)XplSafeRead(Imap.session.served)); - } - - *DataLength = 12; - break; - } - - case 10: { /* XplAtomic Imap.session.badPassword */ - if (Data && (*DataLength > 12)) { - sprintf(Data, "%010lu\r\n", (long unsigned int)XplSafeRead(Imap.session.badPassword)); - } - - *DataLength = 12; - break; - } - - case 11: { /* unsigned char */ - DMC_REPORT_PRODUCT_VERSION(Data, *DataLength); - break; - } - } - - return(TRUE); -} - -/* Management Client Write Function */ -BOOL WriteIMAPVariable(unsigned int Variable, unsigned char *Data, size_t DataLength) -{ - unsigned char *ptr; - unsigned char *ptr2; - BOOL result = TRUE; - - if (!Data || !DataLength) { - return(FALSE); - } - - switch (Variable) { - case 1: { /* unsigned long Imap.session.threads.max */ - ptr = strchr(Data, '\n'); - if (ptr) { - *ptr = '\0'; - } - - ptr2 = strchr(Data, '\r'); - if (ptr2) { - ptr2 = '\0'; - } - - Imap.session.threads.max = atol(Data); - - if (ptr) { - *ptr = '\n'; - } - - if (ptr2) { - *ptr2 = 'r'; - } - - break; - } - - case 6: { /* BOOL Imap.server.disabled */ - if ((toupper(Data[0]) == 'T') || (atol(Data) != 0)) { - Imap.server.disabled = TRUE; - } else if ((toupper(Data[0] == 'F')) || (atol(Data) == 0)) { - Imap.server.disabled = FALSE; - } else { - result = FALSE; - } - - break; - } - - case 9: { /* XplAtomic Imap.session.served */ - ptr = strchr(Data, '\n'); - if (ptr) { - *ptr = '\0'; - } - - ptr2 = strchr(Data, '\r'); - if (ptr2) { - ptr2 = '\0'; - } - - XplSafeWrite(Imap.session.served, atol(Data)); - - if (ptr) { - *ptr = '\n'; - } - - if (ptr2) { - *ptr2 = 'r'; - } - - break; - } - - case 10: { /* XplAtomic Imap.session.badPassword */ - ptr = strchr(Data, '\n'); - if (ptr) { - *ptr = '\0'; - } - - ptr2 = strchr(Data, '\r'); - if (ptr2) { - ptr2 = '\0'; - } - - XplSafeWrite(Imap.session.badPassword, atol(Data)); - - if (ptr) { - *ptr = '\n'; - } - - if (ptr2) { - *ptr2 = 'r'; - } - - break; - } - - case 0: /* #define PRODUCT_VERSION */ - case 2: /* XplAtomic IMAPServerThreads */ - case 3: /* XplAtomic Imap.session.threads.inUse */ - case 4: /* XplAtomic Imap.session.threads.idle */ - case 5: /* BOOL Imap.command.capability.acl.enabled */ - case 7: /* unsigned char Imap.server.hostname[256] */ - case 8: /* unsigned char Imap.server.postmaster[MAXEMAILNAMESIZE + 1] */ - case 11: /* DMC Version */ - default: { - result = FALSE; - break; - } - } - - return(result); -} - static BOOL IMAPSessionAllocCB(void *Buffer, void *ClientData) { @@ -4263,14 +3861,6 @@ XplServiceMain(int argc, char *argv[]) return 1; } - /* Management Client Startup */ - if ((ManagementInit(MSGSRV_AGENT_IMAP, Imap.directory.handle)) - && (ManagementSetVariables(IMAPManagementVariables, sizeof(IMAPManagementVariables) / sizeof(ManagementVariables))) - && (ManagementSetCommands(IMAPManagementCommands, sizeof(IMAPManagementCommands) / sizeof(ManagementCommands)))) { - XplBeginThread(&id, ManagementServer, DMC_MANAGEMENT_STACKSIZE, NULL, ccode); - } - - XplStartMainThread(PRODUCT_SHORT_NAME, &id, IMAPServer, 8192, NULL, ccode); XplUnloadApp(XplGetThreadID()); diff --git a/src/agents/queue/conf.c b/src/agents/queue/conf.c index 605faa9..7e5cf27 100644 --- a/src/agents/queue/conf.c +++ b/src/agents/queue/conf.c @@ -21,6 +21,8 @@ #include +#include "queue.h" + #include #include #include @@ -33,7 +35,6 @@ #include #include "conf.h" -#include "queue.h" #include "domain.h" #include "messages.h" diff --git a/src/agents/queue/queue.c b/src/agents/queue/queue.c index 78cad9f..39b537d 100644 --- a/src/agents/queue/queue.c +++ b/src/agents/queue/queue.c @@ -65,6 +65,49 @@ static int HandleDSN(FILE *data, FILE *control); #define MAX_CHARS_IN_PDBSEARCH 512 +#define FOPEN_CHECK(handle, path, mode) fopen_check(&(handle), (path), (mode), __LINE__) +FILE * +fopen_check(FILE **handle, char *path, char *mode, int line) +{ + LogAssertF(*handle == NULL, "File handle already open on line %d", line); + *handle = fopen(path, mode); + return *handle; +} + +#define FCLOSE_CHECK(f) fclose_check(&(f), __LINE__) +int +fclose_check(FILE **fh, int line) +{ + int ret; + ret = fclose(*fh); + if (ret == 0) { + *fh = NULL; + } else { + LogFailureF("File close failed on line %d: %d", line, errno); + } + return ret; +} + +#define UNLINK_CHECK(path) unlink_check((path), __LINE__) +int +unlink_check(char *path, int line) +{ + int ret; + ret = unlink(path); + LogAssertF(ret == 0, "Unable to delete file %s on line %d: %d", path, line, errno); + return ret; +} + +#define RENAME_CHECK(oldpath, newpath) rename_check((oldpath), (newpath), __LINE__) +int +rename_check(const char *oldpath, const char *newpath, int line) +{ + int ret; + ret = rename(oldpath, newpath); + LogAssertF(ret == 0, "Unable to rename %s to %s on line %d: %d", oldpath, newpath, line, errno); + return ret; +} + static int PDBSearch(char *doc, char *searchString) { @@ -236,9 +279,7 @@ SpoolEntryIDLock(unsigned long id) XplSignalLocalSemaphore(Queue.spoolLocks.semaphores[SPOOL_LOCK_ARRAY_MASK & id]); - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_PQE_LOCK_FULL, LOG_INFO, 0, NULL, NULL, id, 0, NULL, 0); - - XplConsolePrintf("bongoqueue: Unable to lock spool entry %x; table full.\r\n", (unsigned int)id); + Log(LOG_INFO, "Unable to lock spool entry %x, table full", (unsigned int) id); } return(NULL); @@ -300,7 +341,7 @@ AddPushAgent(QueueClient *client, int count; QueuePushClient *temp; - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_ADD_QUEUE_AGENT, LOG_INFO, 0, NULL, NULL, XplHostToLittle(client->conn->socketAddress.sin_addr.s_addr), queue, &port, sizeof(port)); + Log(LOG_INFO, "Adding client on host %s:%d to queue %d", LOGIP(client->conn->socketAddress), port, queue); XplMutexLock(Queue.pushClients.lock); @@ -317,10 +358,7 @@ AddPushAgent(QueueClient *client, Queue.pushClients.array = temp; Queue.pushClients.allocated += PUSHCLIENTALLOC; } else { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_NMAP_OUT_OF_MEMORY, LOG_CRITICAL, 0, "Queue", identifier, (Queue.pushClients.allocated + PUSHCLIENTALLOC) * sizeof(QueuePushClient), 0, NULL, 0); - - XplConsolePrintf("bongoqueue: Out of memory processing user %s, mailbox %s; request size: %d bytes\r\n", "bongoqueue:AddPushAgent", - identifier, (int)((Queue.pushClients.allocated + PUSHCLIENTALLOC) * sizeof(QueuePushClient))); + LogFailureF("Out of memory processing mailbox %s", identifier); return(-1); } } @@ -360,9 +398,9 @@ RemovePushAgentIndex(int index, BOOL force) if ((Queue.pushClients.array[index].errorCount > MAX_PUSHCLIENTS_ERRORS) || force) { if (force) { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_REREGISTER_QUEUE_AGENT, LOG_INFO, 0, NULL, NULL, XplHostToLittle(Queue.pushClients.array[index].address), Queue.pushClients.array[index].queue, &(Queue.pushClients.array[index].port), sizeof(Queue.pushClients.array[index].port)); + Log(LOG_INFO, "Reregistered queue agent"); } else { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_REMOVED_QUEUE_AGENT, LOG_INFO, 0, NULL, NULL, XplHostToLittle(Queue.pushClients.array[index].address), Queue.pushClients.array[index].queue, &(Queue.pushClients.array[index].port), sizeof(Queue.pushClients.array[index].port)); + Log(LOG_INFO, "Removed queue agent"); } if (index < (Queue.pushClients.count - 1)) { @@ -520,7 +558,7 @@ DeliverToStore(NMAPConnections *list, (ccode = ConnFlush(nmap->conn)) == -1) { nmap->error = TRUE; - fclose(fh); + FCLOSE_CHECK(fh); return DELIVER_TRY_LATER; } @@ -620,9 +658,9 @@ ProcessQueueEntry(unsigned char *entryIn) time_t date; struct sockaddr_in saddr; struct stat sb; - FILE *fh; - FILE *data; - FILE *newFH; + FILE *fh = NULL; + FILE *data = NULL; + FILE *newFH = NULL; MIMEReportStruct *report = NULL; MDBValueStruct *vs; QueueClient *client; @@ -647,12 +685,12 @@ StartOver: entryID = strtol(entry, NULL, 16); - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_QUEUE, LOGGER_EVENT_PQE_START, LOG_DEBUG, entryID, NULL, NULL, queue, entryID, NULL, 0); + Log(LOG_DEBUG, "Processing entry %ld on queue %d", entryID, queue); idLock = SpoolEntryIDLock(entryID); if (idLock) { sprintf(path, "%s/c%s.%03d", Conf.spoolPath, entry, queue); - fh = fopen(path, "r+b"); + FOPEN_CHECK(fh, path, "r+b"); } else { ProcessQueueEntryCleanUp(NULL, report); return(FALSE); @@ -661,7 +699,7 @@ StartOver: if (fh) { fgets(line, CONN_BUFSIZE, fh); date = atoi(line + 1); - fclose(fh); + FCLOSE_CHECK(fh); } else { ProcessQueueEntryCleanUp(idLock, report); return(FALSE); @@ -670,6 +708,7 @@ StartOver: /* We've got pre and post processing off queue entries - this is pre */ switch(queue) { case Q_INCOMING: { + FILE *temp = NULL; sb.st_size = -1; qDate = NULL; qFlags = NULL; @@ -678,15 +717,15 @@ StartOver: qFrom = NULL; sprintf(path, "%s/w%s.%03d", Conf.spoolPath, entry, queue); - newFH = fopen(path, "wb"); + FOPEN_CHECK(newFH, path, "wb"); sprintf(path, "%s/c%s.%03d",Conf.spoolPath, entry, queue); if (newFH && (stat(path, &sb) == 0) && (sb.st_size > 8) && ((qEnvelope = (unsigned char *)MemMalloc(sb.st_size + 1)) != NULL) - && ((fh = fopen(path, "rb")) != NULL) - && (fread(qEnvelope, sizeof(unsigned char), sb.st_size, fh) == (size_t)sb.st_size)) { + && ((temp = fopen(path, "rb")) != NULL) + && (fread(qEnvelope, sizeof(unsigned char), sb.st_size, temp) == (size_t)sb.st_size)) { /* Sort the control file as follows: QUEUE_DATE QUEUE_FLAGS @@ -702,7 +741,7 @@ StartOver: QUEUE_RECIP_REMOTE QUEUE_THIRD_PARTY */ - fclose(fh); + fclose(temp); qEnvelope[sb.st_size] = '\0'; @@ -799,15 +838,15 @@ StartOver: /* fixme - if a new queue entry has at least QUEUE_FROM but no recipients we should bounce the message rather than consuming it! */ - fclose(newFH); + FCLOSE_CHECK(newFH); - unlink(path); + UNLINK_CHECK(path); sprintf(path, "%s/w%s.%03d",Conf.spoolPath, entry, queue); - unlink(path); + UNLINK_CHECK(path); sprintf(path, "%s/d%s.msg",Conf.spoolPath, entry); - unlink(path); + UNLINK_CHECK(path); MemFree(qEnvelope); @@ -868,7 +907,7 @@ StartOver: MDBFreeValues(vs); } else { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_QUEUE, LOGGER_EVENT_PQE_FIND_OBJECT_FAILED, LOG_INFO, entryID, cur + 1, "", queue, 0, NULL, 0); + Log(LOG_INFO, "Entry %ld queue %d, can't find %s", entryID, queue, cur + 1); if (ptr2) { *ptr2 = ' '; @@ -925,25 +964,25 @@ StartOver: MemFree(qEnvelope); - fclose(newFH); + FCLOSE_CHECK(newFH); - unlink(path); + UNLINK_CHECK(path); sprintf(path2, "%s/w%s.%03d", Conf.spoolPath, entry, queue); - rename(path2, path); + RENAME_CHECK(path2, path); break; } if (!newFH) { sprintf(path, "%s/w%s.%03d",Conf.spoolPath, entry, queue); - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_FILE_OPEN_FAILURE, LOG_CRITICAL, entryID, path, __FILE__, __LINE__, 0, NULL, 0); + LogFailureF("File open failure. Entry %ld, path %s", entryID, path); } else if (!qEnvelope) { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_NMAP_OUT_OF_MEMORY, LOG_CRITICAL, entryID, __FILE__, NULL, sb.st_size, 0, NULL, 0); + LogFailureF("Out of memory. Entry %ld, size %ld", entryID, sb.st_size); } else if (!fh) { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_FILE_OPEN_FAILURE, LOG_CRITICAL, entryID, path, __FILE__, __LINE__, 0, NULL, 0); + LogFailureF("File open failure. Entry %ld, path %s", entryID, path); } else { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_FILE_OPEN_FAILURE, LOG_CRITICAL, entryID, path, __FILE__, __LINE__, 0, NULL, 0); + LogFailureF("Event file open failure. Entry %ld, path %s", entryID, path); } if (qEnvelope) { @@ -951,17 +990,17 @@ StartOver: } if (fh) { - fclose(fh); + FCLOSE_CHECK(fh); } if (newFH) { - fclose(newFH); + FCLOSE_CHECK(newFH); } - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_WRITE_ERROR, LOG_WARNING, 0, "Spool", "Queue", __LINE__, 0, NULL, 0); + Log(LOG_WARNING, "Write error in queue"); sprintf(path, "%s/w%s.%03d",Conf.spoolPath, entry, queue); - unlink(path); + UNLINK_CHECK(path); ProcessQueueEntryCleanUp(idLock, report); return(TRUE); @@ -974,7 +1013,7 @@ StartOver: /* We move it to the Q_RTS queue and the linger code there will bounce it for us */ sprintf(path, "%s/c%s.%03d", Conf.spoolPath, entry, queue); sprintf(path2, "%s/c%s.%03d", Conf.spoolPath, entry, Q_RTS); - rename(path, path2); + RENAME_CHECK(path, path2); sprintf(path, "%03d%s", Q_RTS, entry); SpoolEntryIDUnlock(idLock); @@ -1022,21 +1061,22 @@ StartOver: bounce = FALSE; sprintf(path, "%s/c%s.%03d", Conf.spoolPath, entry, queue); - fh = fopen(path, "rb"); + FOPEN_CHECK(fh, path, "rb"); sprintf(path, "%s/w%s.%03d", Conf.spoolPath, entry, queue); - newFH = fopen(path, "wb"); + FOPEN_CHECK(newFH, path, "wb"); + if (!fh || !newFH) { if (fh) { - fclose(fh); + FCLOSE_CHECK(fh); } if (newFH) { - fclose(newFH); + FCLOSE_CHECK(newFH); } sprintf(path, "%s/w%s.%03d",Conf.spoolPath, entry, queue); - unlink(path); + UNLINK_CHECK(path); ProcessQueueEntryCleanUp(idLock, report); return(TRUE); @@ -1075,8 +1115,6 @@ StartOver: authenticatedSender[1]='\0'; } - /* LoggerEvent(NMAP.handle.logging, LOGGER_SUBSYSTEM_QUEUE, LOGGER_EVENT_PQE_FROM, LOG_DEBUG, entryID, entry, sender, queue, 0, MIME_TEXT_PLAIN, authenticatedSender? strlen(authenticatedSender) + 1: 1, authenticatedSender? (char *)authenticatedSender: "", NULL, 0); */ - fprintf(newFH, "%s\r\n", line); break; } @@ -1085,12 +1123,12 @@ StartOver: struct sockaddr_in siaddr; if (!data) { - data = fopen(path, "rb"); + FOPEN_CHECK(data, path, "rb"); if (!data) { - fclose(fh); + FCLOSE_CHECK(fh); sprintf(path, "%s/w%s.%03d",Conf.spoolPath, entry, queue); - fclose(newFH); - unlink(path); + FCLOSE_CHECK(newFH); + UNLINK_CHECK(path); ProcessQueueEntryCleanUp(idLock, report); return(TRUE); } @@ -1117,11 +1155,10 @@ StartOver: vs = MDBCreateValueStruct(Agent.agent.directoryHandle, NULL); if (!MsgFindObject(recipient, NULL, NULL, &siaddr, vs)) { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_QUEUE, LOGGER_EVENT_PQE_FIND_OBJECT_FAILED, LOG_WARNING, entryID, recipient, "", queue, 0, NULL, 0); - + Log(LOG_WARNING, "User %s unknown, entry %ld", recipient, entryID); status = DELIVER_USER_UNKNOWN; } else { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_QUEUE, LOGGER_EVENT_PQE_REMOTE_NMAP, LOG_DEBUG, entryID, entry, line + 1, queue, XplHostToLittle(siaddr.sin_addr.s_addr), NULL, 0); + Log(LOG_DEBUG, "Delivering %s on queue %d to %s", entry, queue, line+1); status = DeliverToStore(&list, &siaddr, NMAP_DOCTYPE_CAL, sender, authenticatedSender, dataFilename, data, dSize, recipient, mailbox, flags); if (Agent.agent.state == BONGO_AGENT_STATE_STOPPING) { status = DELIVER_TRY_LATER; @@ -1135,7 +1172,7 @@ StartOver: } if (statusconn, 0); ConnFree(client->conn); @@ -1573,7 +1613,7 @@ StartOver: QueueClientFree(client); if (fh) { - fclose(fh); + FCLOSE_CHECK(fh); } fh = NULL; @@ -1586,7 +1626,7 @@ StartOver: ConnWriteF(client->conn, "6020 %03d-%s %ld %ld %ld\r\n", queue, entry, (unsigned long)sb.st_size, dSize, lines); ConnWriteFile(client->conn, fh); - fclose(fh); + FCLOSE_CHECK(fh); fh = NULL; sprintf(client->entry.workQueue, "%03d-%s", queue, entry); @@ -1598,7 +1638,7 @@ StartOver: client->entry.report = report; if (!HandleCommand(client)) { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_QUEUE, LOGGER_EVENT_PQE_FAILED, LOG_WARNING, entryID, entry, NULL, queue, XplHostToLittle(saddr.sin_addr.s_addr), &(Queue.pushClients.array[used].port), sizeof(Queue.pushClients.array[used].port)); + LogFailureF("Couldn't handle command on entry %s for host %s", entry, LOGIP(saddr)); } /* fixme - evaluate this section. @@ -1673,7 +1713,7 @@ StartOver: sprintf(path, "%s/c%s.%03d", Conf.spoolPath, entry, queue); sprintf(path2, "%s/c%s.%03d", Conf.spoolPath, entry, i); - rename(path, path2); + RENAME_CHECK(path, path2); sprintf(path, "%03d%s", i, entry); SpoolEntryIDUnlock(idLock); @@ -1693,7 +1733,7 @@ StartOver: QDBHandleRelease(handle); } - fh = fopen(path,"rb"); + FOPEN_CHECK(fh, path, "rb"); keep = FALSE; if (fh) { do { @@ -1723,9 +1763,7 @@ StartOver: if (ptr2) { if ((handle = QDBHandleAlloc()) != NULL) { ccode = QDBAdd(handle, ptr2 + 1, entryID, queue); - if (ccode == -1) { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_DATABASE, LOGGER_EVENT_DATABASE_INSERT_ERROR, LOG_ERROR, 0, ptr2 + 1, NULL, ccode, 0, NULL, 0); - } + LogAssertF(ccode != -1, "Database insert error: %s", ptr2 + 1); QDBHandleRelease(handle); } @@ -1741,7 +1779,7 @@ StartOver: } } } while (!feof(fh) && !ferror(fh)); - fclose(fh); + FCLOSE_CHECK(fh); } else { keep = TRUE; } @@ -1750,16 +1788,16 @@ StartOver: if (bounce) { /* Call the bouncing code */ sprintf(path2, "%s/d%s.msg", Conf.spoolPath, entry); - data = fopen(path2, "rb"); - fh = fopen(path, "rb"); + FOPEN_CHECK(data, path2, "rb"); + FOPEN_CHECK(fh, path, "rb"); if (fh && data && 0 == HandleDSN(data, fh)) { - fclose(data); + FCLOSE_CHECK(data); /* If we're not keeping the file, we can ignore its contents */ if (keep) { sprintf(path2, "%s/w%s.%03d", Conf.spoolPath, entry, queue); - newFH = fopen(path2, "wb"); + FOPEN_CHECK(newFH, path2, "wb"); if (newFH) { /* Now remove the bounced entries */ while (!feof(fh) && !ferror(fh)) { @@ -1777,27 +1815,27 @@ StartOver: } } - fclose(fh); - fclose(newFH); + FCLOSE_CHECK(fh); + FCLOSE_CHECK(newFH); - unlink(path); - rename(path2, path); + UNLINK_CHECK(path); + RENAME_CHECK(path2, path); } else { - fclose(fh); + FCLOSE_CHECK(fh); } } else { - fclose(fh); + FCLOSE_CHECK(fh); } } else { if (fh) { - fclose(fh); + FCLOSE_CHECK(fh); } if (data) { - fclose(data); + FCLOSE_CHECK(data); } - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_FILE_OPEN_FAILURE, LOG_CRITICAL, entryID, path, __FILE__, __LINE__, 0, NULL, 0); + LogFailureF("File open failure: entry %ld, path %s", entryID, path); ProcessQueueEntryCleanUp(idLock, report); return(TRUE); @@ -1807,10 +1845,10 @@ StartOver: if (!keep) { XplSafeDecrement(Queue.queuedLocal); - unlink(path); + UNLINK_CHECK(path); sprintf(path, "%s/d%s.msg",Conf.spoolPath, entry); - unlink(path); + UNLINK_CHECK(path); break; } @@ -1827,13 +1865,13 @@ StartOver: } sprintf(path, "%s/w%s.%03d", Conf.spoolPath, entry, queue); - newFH = fopen(path, "wb"); + FOPEN_CHECK(newFH, path, "wb"); sprintf(path, "%s/d%s.msg", Conf.spoolPath, entry); - data = fopen(path, "rb"); + FOPEN_CHECK(data, path, "rb"); sprintf(path, "%s/c%s.%03d", Conf.spoolPath, entry, queue); - fh = fopen(path, "rb"); + FOPEN_CHECK(fh, path, "rb"); if (fh && newFH && data) { XplSafeIncrement(Queue.remoteDeliveryFailed); @@ -1878,42 +1916,42 @@ StartOver: } } - fclose(newFH); - fclose(fh); + FCLOSE_CHECK(newFH); + FCLOSE_CHECK(fh); /* Still got path from above */ - unlink(path); + UNLINK_CHECK(path); sprintf(path2, "%s/w%s.%03d", Conf.spoolPath, entry, queue); - rename(path2, path); + RENAME_CHECK(path2, path); - fh = fopen(path, "rb"); + FOPEN_CHECK(fh, path, "rb"); if (fh) { HandleDSN(data, fh); - fclose(fh); + FCLOSE_CHECK(fh); } else { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_FILE_OPEN_FAILURE, LOG_CRITICAL, entryID, path, __FILE__, __LINE__, 0, NULL, 0); + LogFailureF("Couldn't open path %s (%ld)", path, entryID); } - fclose(data); + FCLOSE_CHECK(data); sprintf(path, "%s/c%s.%03d", Conf.spoolPath, entry, queue); - unlink(path); + UNLINK_CHECK(path); sprintf(path, "%s/d%s.msg", Conf.spoolPath, entry); - unlink(path); + UNLINK_CHECK(path); XplSafeDecrement(Queue.queuedLocal); } else { if (data) { - fclose(data); + FCLOSE_CHECK(data); } if (fh) { - fclose(fh); + FCLOSE_CHECK(fh); } if (newFH) { - fclose(newFH); + FCLOSE_CHECK(newFH); } } @@ -1923,7 +1961,7 @@ StartOver: count = 0; sprintf(path, "%s/c%s.%03d", Conf.spoolPath, entry, Q_RTS); sprintf(path2, "%s/c%s.%03d", Conf.spoolPath, entry, Q_INCOMING); - rename(path, path2); + RENAME_CHECK(path, path2); sprintf(path, "%03d%s", Q_INCOMING, entry); } @@ -2443,7 +2481,7 @@ HandleDSN(FILE *data, FILE *control) fprintf (stderr, "could not open rtsData\n"); fclose(rtsControl); sprintf(path, "%s/d%07lx.msg", Conf.spoolPath, id); - unlink(path); + UNLINK_CHECK(path); return -1; } @@ -2452,10 +2490,10 @@ HandleDSN(FILE *data, FILE *control) fclose(rtsData); sprintf(path, "%s/d%07lx.msg", Conf.spoolPath, id); - unlink(path); + UNLINK_CHECK(path); sprintf(path, "%s/c%07lx.%03d", Conf.spoolPath, id, Q_INCOMING); - unlink(path); + UNLINK_CHECK(path); SpoolEntryIDUnlock(idLock); return 0; @@ -2797,7 +2835,7 @@ CreateQueueThreads(BOOL failed) current++; CHOP_NEWLINE(path); - unlink(path); + UNLINK_CHECK(path); } } @@ -2805,7 +2843,7 @@ CreateQueueThreads(BOOL failed) } sprintf(path, "%s/killfile", MsgGetDBFDir(NULL)); - unlink(path); + UNLINK_CHECK(path); XplCloseDir(dirP); @@ -3032,7 +3070,7 @@ CommandQabrt(void *param) client->entry.control = NULL; sprintf(client->path,"%s/c%07lx.in", Conf.spoolPath, client->entry.id); - unlink(client->path); + UNLINK_CHECK(client->path); } if (client->entry.data) { @@ -3040,7 +3078,7 @@ CommandQabrt(void *param) client->entry.data = NULL; sprintf(client->path,"%s/d%07lx.msg",Conf.spoolPath, client->entry.id); - unlink(client->path); + UNLINK_CHECK(client->path); } if (client->entry.work) { fclose(client->entry.work); @@ -3048,7 +3086,7 @@ CommandQabrt(void *param) if (client->entry.workQueue[0] != '\0') { sprintf(client->path,"%s/w%s.%s",Conf.spoolPath, client->entry.workQueue + 4, client->entry.workQueue); - unlink(client->path); + UNLINK_CHECK(client->path); } } @@ -3333,7 +3371,7 @@ CommandQcrea(void *param) } else { fclose(client->entry.control); sprintf(client->path, "%s/c%07lx.in", Conf.spoolPath, id); - unlink(client->path); + UNLINK_CHECK(client->path); return(ConnWrite(client->conn, MSG5221SPACELOW, sizeof(MSG5221SPACELOW) - 1)); } @@ -3368,10 +3406,10 @@ CommandQdele(void *param) LockQueueEntry(ptr+4, atoi(ptr)); */ sprintf(client->path, "%s/c%s.%s", Conf.spoolPath, ptr + 4, ptr); - unlink(client->path); + UNLINK_CHECK(client->path); sprintf(client->path, "%s/d%s.msg", Conf.spoolPath, ptr + 4); - unlink(client->path); + UNLINK_CHECK(client->path); /* FIXME: close out the file handles? */ @@ -3400,15 +3438,15 @@ CommandQdone(void *param) sprintf(client->path, "%s/w%s.%s", Conf.spoolPath, client->entry.workQueue + 4, client->entry.workQueue); sprintf(path, "%s/c%s.%s", Conf.spoolPath, client->entry.workQueue + 4, client->entry.workQueue); if ((stat(client->path, &sb1) == 0) && (stat(path, &sb2) == 0)) { - unlink(path); - rename(client->path, path); + UNLINK_CHECK(path); + RENAME_CHECK(client->path, path); } else { if (stat(client->path, &sb) == 0) { /* Our new queue file exists, everything still ok */ - rename(client->path, path); + RENAME_CHECK(client->path, path); } else { /* got to keep the old one */ - unlink(client->path); + UNLINK_CHECK(client->path); } } @@ -3883,12 +3921,12 @@ CommandQmove(void *param) if (stat(client->path, &sb) == 0) { sprintf(path, "%s/c%s.%03d", Conf.spoolPath, ptr + 4, atoi(ptr)); - rename(client->path, path); + RENAME_CHECK(client->path, path); ccode = ConnWrite(client->conn, MSG1000OK, sizeof(MSG1000OK) - 1); } else { sprintf(client->path, "%s/d%s.msg", Conf.spoolPath, ptr + 4); - unlink(client->path); + UNLINK_CHECK(client->path); ccode = ConnWrite(client->conn, MSG4224NOENTRY, sizeof(MSG4224NOENTRY) - 1); } @@ -3953,7 +3991,7 @@ CommandQrcp(void *param) sprintf(client->path,"%s/c%07lx.in",Conf.spoolPath, client->entry.id); sprintf(path, "%s/c%07lx.%03ld", Conf.spoolPath, client->entry.id, client->entry.target); - rename(client->path, path); + RENAME_CHECK(client->path, path); sprintf(client->path, "%03ld%lx", client->entry.target, client->entry.id); @@ -3982,7 +4020,7 @@ CommandQrcp(void *param) client->entry.control = NULL; sprintf(client->path, "%s/c%07lx.in", Conf.spoolPath, id); - unlink(client->path); + UNLINK_CHECK(client->path); } sprintf(client->path, "%s/c%07lx.in", Conf.spoolPath, client->entry.id); @@ -4143,7 +4181,7 @@ CommandQrun(void *param) sprintf(client->path,"%s/c%07lx.in",Conf.spoolPath, client->entry.id); sprintf(path, "%s/c%07lx.%03ld", Conf.spoolPath, client->entry.id, client->entry.target); - rename(client->path, path); + RENAME_CHECK(client->path, path); XplSafeIncrement(Queue.queuedLocal); @@ -4213,11 +4251,11 @@ CommandQsrchDomain(void *param) ccode = ConnWrite(client->conn, MSG1000OK, sizeof(MSG1000OK) - 1); } } else { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_DATABASE, LOGGER_EVENT_DATABASE_FIND_ERROR, LOG_ERROR, 0, ptr, NULL, ccode, 0, NULL, 0); + LogFailureF("Couldn't find %s in QDB", ptr); ccode = ConnWrite(client->conn, MSG4261NODOMAIN, sizeof(MSG4261NODOMAIN) - 1); } } else { - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_NMAP_OUT_OF_MEMORY, LOG_CRITICAL, 0, client->buffer, NULL, sizeof(MDBValueStruct), 0, NULL, 0); + LogFailure("Out of memory"); ccode = ConnWrite(client->conn, MSG5230NOMEMORYERR, sizeof(MSG5230NOMEMORYERR) - 1); } @@ -4776,6 +4814,6 @@ CommandQflush(void *param) QueueClient *client = (QueueClient *)param; Queue.flushNeeded = TRUE; - + return (ConnWrite(client->conn, MSG1000OK, sizeof(MSG1000OK) - 1)); } diff --git a/src/agents/queue/queue.h b/src/agents/queue/queue.h index 4e74642..e1cf148 100644 --- a/src/agents/queue/queue.h +++ b/src/agents/queue/queue.h @@ -22,8 +22,8 @@ #ifndef QUEUE_H #define QUEUE_H -#include "conf.h" #include "queued.h" +#include "conf.h" #define SPOOL_LOCK_ARRAY_SIZE 256 #define SPOOL_LOCK_IDARRAY_SIZE 64 @@ -92,6 +92,11 @@ typedef struct _Queue { extern MessageQueue Queue; +FILE * fopen_check(FILE **handle, char *path, char *mode, int line); +int fclose_check(FILE **handle, int line); +int unlink_check(char *path, int line); +int rename_check(const char *oldpath, const char *newpath, int line); + BOOL QueueInit(void); void QueueShutdown(void); diff --git a/src/agents/queue/queued.c b/src/agents/queue/queued.c index aea48a3..35b19da 100644 --- a/src/agents/queue/queued.c +++ b/src/agents/queue/queued.c @@ -21,9 +21,11 @@ #include +#include "queue.h" +#include "queued.h" + #include #include -#include #include #include #include @@ -32,9 +34,7 @@ #include #include -#include "queued.h" #include "conf.h" -#include "queue.h" #include "domain.h" #include "messages.h" @@ -122,7 +122,7 @@ CommandAuth(void *param) return(ConnWrite(client->conn, MSG1000OK, sizeof(MSG1000OK) - 1)); } - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_AUTH, LOGGER_EVENT_WRONG_SYSTEM_AUTH, LOG_NOTICE, 0, NULL, NULL, XplHostToLittle(client->conn->socketAddress.sin_addr.s_addr), 0, NULL, 0); + Log(LOG_NOTICE, "SYSTEM AUTH failed from host %s", LOGIP(client->conn->socketAddress)); ConnWrite(client->conn, MSG3242BADAUTH, sizeof(MSG3242BADAUTH) - 1); @@ -162,7 +162,7 @@ CommandPass(void *param) return(ConnWrite(client->conn, MSG4120USERLOCKED, sizeof(MSG4120USERLOCKED) - 1)); } - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_AUTH, LOGGER_EVENT_WRONG_USER_AUTH, LOG_NOTICE, 0, ptr, NULL, XplHostToLittle(client->conn->socketAddress.sin_addr.s_addr), 0, NULL, 0); + Log(LOG_NOTICE, "PASS USER failed for user from host %s", LOGIP(client->conn->socketAddress)); } else if ( (toupper(ptr[0]) == 'S') && (toupper(ptr[1]) == 'Y') && (toupper(ptr[2]) == 'S') @@ -180,7 +180,7 @@ CommandPass(void *param) } #endif - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_AUTH, LOGGER_EVENT_WRONG_SYSTEM_AUTH, LOG_NOTICE, 0, NULL, NULL, XplHostToLittle(client->conn->socketAddress.sin_addr.s_addr), 0, NULL, 0); + Log(LOG_NOTICE, "PASS SYSTEM failed from host %s", LOGIP(client->conn->socketAddress)); } } @@ -296,8 +296,7 @@ HandleCommand(QueueClient *client) ccode = ConnWrite(client->conn, MSG3240NOAUTH, sizeof(MSG3240NOAUTH) - 1); } - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_UNHANDLED, LOGGER_EVENT_UNHANDLED_REQUEST, LOG_INFO, 0, "Queue", - client->buffer, XplHostToLittle(client->conn->socketAddress.sin_addr.s_addr), 0, NULL, 0); + Log(LOG_INFO, "Handled command from %s", LOGIP(client->conn->socketAddress)); } } else if (ccode == -1) { break; @@ -444,24 +443,26 @@ CheckDiskspace(BongoAgent *agent) { unsigned long freeBlocks; unsigned long bytesPerBlock; + unsigned long wantFree; bytesPerBlock = XplGetDiskBlocksize(Conf.spoolPath); freeBlocks = XplGetDiskspaceFree(Conf.spoolPath); + wantFree = (Conf.minimumFree / bytesPerBlock) + 1; if (freeBlocks != 0x7f000000) { - if (freeBlocks < ((Conf.minimumFree / bytesPerBlock) + 1)) { + if (freeBlocks < wantFree) { /* BUG ALERT: */ /* With a block size of 4KB, freeBlocks could */ /* overflow if a volume had more than 16 TB. */ Agent.flags |= QUEUE_AGENT_DISK_SPACE_LOW; - LoggerEvent(Agent.agent.loggingHandle, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_DISKSPACE_LOW, LOG_ERROR, 0, Conf.spoolPath, NULL, freeBlocks, (Conf.minimumFree/bytesPerBlock)+1, NULL, 0); + Log(LOG_ERROR, "Disk space for %s low: have %ld free, want %ld.", Conf.spoolPath, freeBlocks, wantFree); } else { Agent.flags &= ~QUEUE_AGENT_DISK_SPACE_LOW; } } else { - XplConsolePrintf("bongoqueue: The OS failed to respond to a disk space query\r\n"); + Log(LOG_NOTICE, "Couldn't work out disk space free for %s", Conf.spoolPath); } } @@ -523,6 +524,8 @@ XplServiceMain(int argc, char *argv[]) int ccode; int startupOpts; + LogStart(); + if (XplSetRealUser(MsgGetUnprivilegedUser()) < 0) { XplConsolePrintf(AGENT_NAME ": Could not drop to unprivileged user '%s'\r\n" AGENT_NAME ": exiting.\n", MsgGetUnprivilegedUser()); return -1; @@ -579,6 +582,8 @@ XplServiceMain(int argc, char *argv[]) /* Start the server thread */ XplStartMainThread(AGENT_NAME, &id, QueueServer, 8192, NULL, ccode); + + LogShutdown(); XplUnloadApp(XplGetThreadID()); diff --git a/src/agents/queue/queued.h b/src/agents/queue/queued.h index ef3d575..ff413cc 100644 --- a/src/agents/queue/queued.h +++ b/src/agents/queue/queued.h @@ -22,6 +22,8 @@ #ifndef QUEUED_H #define QUEUED_H +#define LOGGERNAME "queue" + #include #include #include diff --git a/src/agents/smtp/smtpd.c b/src/agents/smtp/smtpd.c index 75ca891..cc10900 100644 --- a/src/agents/smtp/smtpd.c +++ b/src/agents/smtp/smtpd.c @@ -1697,8 +1697,8 @@ DeliverSMTPMessage (ConnectionStruct * Client, unsigned char *Sender, else { /* The other server supports ESMTP */ - /* Should we deliver via SSL? */ - if (AllowClientSSL && (Extensions & EXT_TLS)) { + // SSL delivery disabled per bug #9536 + if (0 && AllowClientSSL && (Extensions & EXT_TLS)) { snprintf (Answer, sizeof (Answer), "STARTTLS\r\n"); if (ConnWrite(Client->remotesmtp.conn, Answer, strlen(Answer)) < 1) { DELIVER_ERROR (DELIVER_TRY_LATER); @@ -2165,22 +2165,22 @@ DeliverRemoteMessage (ConnectionStruct * Client, unsigned char *Sender, /* Clean up a potential ip address in the host name (e.g. jdoe@[1.1.1.1] ) */ if (Host[0] == '[') { + int host; ptr = strchr (Host, ']'); if (ptr) *ptr = '\0'; memmove (Host, Host + 1, strlen (Host + 1) + 1); /* Check for an IP address */ - int host; - Client->remotesmtp.conn->socketAddress.sin_addr.s_addr = host; if ((host = inet_addr (Host)) != -1) { GoByAddr = TRUE; UsingMX = FALSE; } + Client->remotesmtp.conn->socketAddress.sin_addr.s_addr = host; } if (!GoByAddr && UseRelayHost) { - int relayhost; - Client->remotesmtp.conn->socketAddress.sin_addr.s_addr=relayhost; + int relayhost = inet_addr(RelayHost); + Client->remotesmtp.conn->socketAddress.sin_addr.s_addr = relayhost; if (relayhost == -1) { status=XplDnsResolve(RelayHost, &DNSARec, XPL_RR_A); /*fprintf (stderr, "%s:%d Looked up relay host %s: %d\n", __FILE__, __LINE__, RelayHost, status);*/ @@ -3697,7 +3697,7 @@ ProcessLocalEntry (ConnectionStruct * Client, unsigned long Size, static void HandleQueueConnection (void *ClientIn) { - int ReplyInt, Queue; + int ReplyInt, Queue = Q_INCOMING; unsigned char Reply[1024]; ConnectionStruct *Client = (ConnectionStruct *) ClientIn; unsigned char *ptr; @@ -5026,11 +5026,10 @@ int XplServiceMain (int argc, char *argv[]) int ccode; XplThreadID ID; + LogStart(); /* Done binding to ports, drop privs permanently */ if (XplSetEffectiveUser (MsgGetUnprivilegedUser ()) < 0) { - XplConsolePrintf - ("bongosmtp: Could not drop to unprivileged user '%s', exiting.\n", - MsgGetUnprivilegedUser ()); + Log(LOG_ERROR, "Could not drop to unprivileged user %s", MsgGetUnprivilegedUser()); return 1; } XplInit(); @@ -5055,15 +5054,12 @@ int XplServiceMain (int argc, char *argv[]) } else { MemoryManagerClose (MSGSRV_AGENT_SMTP); - - XplConsolePrintf - ("SMTPD: Unable to create connection pool; shutting down.\r\n"); + Log(LOG_ERROR, "Unable to create connection pool, shutting down"); return (-1); } } else { - XplConsolePrintf - ("SMTPD: Unable to initialize memory manager; shutting down.\r\n"); + Log(LOG_ERROR, "Unable to initialize memory manager, shutting down"); return (-1); } @@ -5071,10 +5067,7 @@ int XplServiceMain (int argc, char *argv[]) MDBInit (); if ((SMTPDirectoryHandle = (MDBHandle) MsgInit ()) == NULL) { - XplBell (); - XplConsolePrintf - ("\rSMTPD: Invalid directory credentials; exiting!\n"); - XplBell (); + Log(LOG_ERROR, "Invalid directory credentials, shutting down"); MemoryManagerClose (MSGSRV_AGENT_SMTP); @@ -5085,7 +5078,6 @@ int XplServiceMain (int argc, char *argv[]) XplRWLockInit (&ConfigLock); - LogStartup (); for (ccode = 1; argc && (ccode < argc); ccode++) { if (XplStrNCaseCmp (argv[ccode], "--forwarder=", 12) == 0) { @@ -5097,7 +5089,7 @@ int XplServiceMain (int argc, char *argv[]) ReadConfiguration (); if (ServerSocketInit () < 0) { - XplConsolePrintf ("bongosmtp: Exiting.\n"); + Log(LOG_WARN, "Can't open ports, exiting"); return 1; } @@ -5124,9 +5116,7 @@ int XplServiceMain (int argc, char *argv[]) /* Done binding to ports, drop privs permanently */ if (XplSetRealUser (MsgGetUnprivilegedUser ()) < 0) { - XplConsolePrintf - ("bongosmtp: Could not drop to unprivileged user '%s', exiting.\n", - MsgGetUnprivilegedUser ()); + Log(LOG_ERROR, "Could not drop to unprivileged user %s", MsgGetUnprivilegedUser()); return 1; } diff --git a/src/apps/config/Bongo.rules b/src/apps/config/Bongo.rules index c930f8a..c9aa5fb 100644 --- a/src/apps/config/Bongo.rules +++ b/src/apps/config/Bongo.rules @@ -1,7 +1,16 @@ # -*- Makefile -*- sbin_PROGRAMS += bongo-config +conf_defaults = \ + src/apps/config/config/manager \ + src/apps/config/config/antivirus \ + src/apps/config/config/imap \ + src/apps/config/config/pop3 \ + src/apps/config/config/mailproxy \ + src/apps/config/config/antispam + bongo_config_SOURCES := \ + $(conf_defaults) \ src/apps/config/config.h \ src/apps/config/config.c @@ -19,18 +28,8 @@ bongo_config_LDADD := \ $(GNUTLS_LIBS) \ $(ALL_LIBS) -conf_defaults = \ - src/apps/config/config/manager \ - src/apps/config/config/antivirus \ - src/apps/config/config/imap \ - src/apps/config/config/pop3 \ - src/apps/config/config/mailproxy \ - src/apps/config/config/antispam - confdir = $(pkgdatadir)/conf -conf_SOURCES = $(conf_defaults) - conf_DATA := \ src/apps/config/default.set diff --git a/src/apps/storetool/Bongo.rules b/src/apps/storetool/Bongo.rules index c823ccf..06f3f83 100644 --- a/src/apps/storetool/Bongo.rules +++ b/src/apps/storetool/Bongo.rules @@ -6,7 +6,8 @@ pkgpythonstoretool_PYTHON := \ src/apps/storetool/bongo/storetool/CalendarCommands.py \ src/apps/storetool/bongo/storetool/ContactCommands.py \ src/apps/storetool/bongo/storetool/InteractiveCommands.py \ - src/apps/storetool/bongo/storetool/MailCommands.py + src/apps/storetool/bongo/storetool/MailCommands.py \ + src/apps/storetool/bongo/storetool/ExportMailbox.py src/apps/storetool/bongo-storetool: $(top_builddir)/src/libs/python/bongo-python-wrapper $(INSTALL) -m 755 $< $@ diff --git a/src/apps/storetool/bongo/storetool/ExportMailbox.py b/src/apps/storetool/bongo/storetool/ExportMailbox.py new file mode 100644 index 0000000..522d158 --- /dev/null +++ b/src/apps/storetool/bongo/storetool/ExportMailbox.py @@ -0,0 +1,119 @@ +import os +import re +import socket +import errno +import cStringIO +import mailbox +import email, email.Generator +import sys + +from time import time, mktime, strptime, ctime, sleep +from rfc822 import Message, parsedate_tz, mktime_tz + +class MboxMailbox(mailbox.PortableUnixMailbox): + def __init__(self,file): + mailbox.PortableUnixMailbox.__init__(self, file, email.message_from_file) + self.boxname = file + self.content = "" + + def add(self, msg): + fp = cStringIO.StringIO() + g = email.Generator.Generator(fp, mangle_from_=False) + envelope = email.message_from_string(msg) + g.flatten(envelope, unixfrom=True) + self.content += "%s" % fp.getvalue() + + def write(self): + outfile=file(self.boxname, "wb") + outfile.write("%s\n" % self.content) + outfile.close() + +class MaildirMailbox(mailbox.Maildir): + def __init__(self,file): + if file[-1] == "/": + self.boxname = file + else: + self.boxname = file + "/" + + while 1: + try: + os.makedirs(self.boxname + "cur") + os.makedirs(self.boxname + "new") + os.makedirs(self.boxname + "tmp") + except OSError, err: + if err.errno == errno.EEXIST: + break + mailbox.Maildir.__init__(self, file, email.message_from_file) + + def tmp_open(self): + hostname = socket.gethostname() + pid = os.getpid() + while 1: + name = "tmp/%.6f%05d.%s" % (time(), pid, hostname) + try: + os.stat(name) + except OSError, err: + if err.errno == errno.ENOENT: + break + + fd = os.open(name, os.O_WRONLY|os.O_EXCL|os.O_CREAT, 0600) + return (name, fd) + + + def status(self, message): + status = message.get("Status") + if status == "O": + dir = "cur" + info = "" + elif status == "RO": + dir = "cur" + info = ":2,S" + else: + dir = "new" + info = "" + + return (dir, info) + + def get_delivery_time(self, message): + dtime = None + if message.has_key("Date"): + dtime = mktime_tz(parsedate_tz(message["Date"])) + + return dtime + + def write_message(self, raw_msg, fd, tmp): + try: + os.write(fd, raw_msg) + os.fsync(fd) + os.close(fd) + except OSError, err: + os.unlink(tmp) + raise Error("unable to fsync() or close() temp file: %s" % err) + + + def finish_message(self, tmp, dir, info, dtime): + base_name = os.path.basename(tmp) + dst_name = os.path.join(dir, base_name + info) + os.link(tmp, dst_name) + + if dtime is not None: + atime = os.stat(dst_name).st_atime + os.utime(dst_name, (atime, dtime)) + + return dst_name + + def add(self, raw_msg): + start_dir = os.getcwd() + os.chdir(self.boxname) + (tmp, fd) = self.tmp_open() + + try: + fp = cStringIO.StringIO(raw_msg) + message = Message(fp) + (dir, info) = self.status(message) + dtime = self.get_delivery_time(message) + self.write_message(raw_msg, fd, tmp) + dst_name = self.finish_message(tmp, dir, info, dtime) + finally: + os.unlink(tmp) + os.chdir(start_dir) diff --git a/src/apps/storetool/bongo/storetool/MailCommands.py b/src/apps/storetool/bongo/storetool/MailCommands.py index fa637bb..464cf82 100644 --- a/src/apps/storetool/bongo/storetool/MailCommands.py +++ b/src/apps/storetool/bongo/storetool/MailCommands.py @@ -3,37 +3,50 @@ import logging import mailbox import sys +from gettext import gettext as _ + from bongo.cmdparse import Command from bongo.BongoError import BongoError from libbongo.libs import bongojson, msgapi from bongo.store.StoreClient import DocTypes, StoreClient +from bongo.storetool.ExportMailbox import MboxMailbox, MaildirMailbox -class MailStoreCommand(Command): +class MailImportCommand(Command): log = logging.getLogger("Bongo.StoreTool") def __init__(self): - Command.__init__(self, "mail-store", aliases=["ms"], - summary="Store individual mail messages", + Command.__init__(self, "mail-import", aliases=["mi"], + summary="Import mail into the store", usage="%prog %cmd [ ...]") - def ImportFile(self, store, file): - if file == "-": - import tempfile - fd = tempfile.TemporaryFile(mode="w+b") - try: - for line in sys.stdin: fd.write(line) - except StopIteration: pass - fd.seek(0) - else: - fd = open(file) + self.add_option("-t", "--type", type="string", default="mbox", help=_("Type of mail source [mbox or maildir], defaults to mbox")) + self.add_option("-f", "--folder", type="string", default="INBOX", help=_("Folder to import to, defaults to INBOX")) - mbox = mailbox.PortableUnixMailbox(fd, email.message_from_file) + def ImportFile(self, store, file, type, folder): + collection = "/mail/" + folder + store.Create(collection, existingOk=True) - for msg in mbox: + if type == "mbox": + if file == "-": + import tempfile + fd = tempfile.TemporaryFile(mode="w+b") + try: + for line in sys.stdin: fd.write(line) + except StopIteration: pass + fd.seek(0) + else: + fd = open(file) + + mailstore = mailbox.PortableUnixMailbox(fd, email.message_from_file) + elif type == "maildir": + mailstore = mailbox.Maildir(file, email.message_from_file) + + for msg in mailstore: data = msg.as_string(True) - store.Write("/mail/INBOX", DocTypes.Mail, data) + store.Write(collection, DocTypes.Mail, data) - fd.close() + if fd: + fd.close() def Run(self, options, args): if len(args) == 0: @@ -45,7 +58,56 @@ class MailStoreCommand(Command): try: for file in args: try: - self.ImportFile(store, file) + self.ImportFile(store, file, options.type, options.folder) + except IOError, e: + print str(e) + finally: + store.Quit() + + +class MailExportCommand(Command): + log = logging.getLogger("Bongo.StoreTool") + + def __init__(self): + Command.__init__(self, "mail-export", aliases=["me"], + summary="Export mail from the store", + usage="%prog %cmd [ ...]") + + self.add_option("-t", "--type", type="string", default="mbox", help=_("Type of mail destination [mbox or maildir], defaults to mbox")) + self.add_option("-f", "--folder", type="string", default="INBOX", help=_("Folder to export from, defaults to INBOX")) + + def ExportFile(self, store, file, type, folder): + collection = "/mail/" + folder + mail_list = list(store.List(collection, ["nmap.guid"])) + + if type == "mbox": + mbox = MboxMailbox(file) + for mail in mail_list: + if mail.type != DocTypes.Mail: + continue + msg = store.Read(mail.props["nmap.guid"]) + mbox.add(msg) + mbox.write() + elif type == "maildir": + maildir = MaildirMailbox(file) + for mail in mail_list: + if mail.type != DocTypes.Mail: + continue + msg = store.Read(mail.props["nmap.guid"]) + maildir.add(msg) + + + def Run(self, options, args): + if len(args) == 0: + self.print_help() + self.exit() + + store = StoreClient(options.user, options.store) + + try: + for file in args: + try: + self.ExportFile(store, file, options.type, options.folder) except IOError, e: print str(e) finally: diff --git a/src/libs/bongoutil/hashtable.c b/src/libs/bongoutil/hashtable.c index b4f8c71..b7f326a 100644 --- a/src/libs/bongoutil/hashtable.c +++ b/src/libs/bongoutil/hashtable.c @@ -223,7 +223,7 @@ BongoHashtableCreateFull(int buckets, DeleteFunction keydeletefunc, DeleteFunction valuedeletefunc) { BongoHashtable *table; - const int size = sizeof(BongoHashtable) + buckets * sizeof(struct BongoHashtableEntry *); + const int size = ALIGN_SIZE(sizeof(BongoHashtable), ALIGNMENT) + buckets * ALIGN_SIZE(sizeof(struct BongoHashtableEntry *), ALIGNMENT); table = MemMalloc(size); if (!table) { @@ -237,7 +237,7 @@ BongoHashtableCreateFull(int buckets, table->keydeletefunc = keydeletefunc; table->valuedeletefunc = valuedeletefunc; - memset(&(table->buckets[0]), 0, buckets * sizeof(struct BongoHashtableEntry *)); + //memset(&(table->buckets[0]), 0, buckets * ALIGN_SIZE(sizeof(struct BongoHashtableEntry *), ALIGNMENT)); return table; } diff --git a/src/libs/mdb-xldap/mdbldap.c b/src/libs/mdb-xldap/mdbldap.c index 3b41d37..3093c2d 100644 --- a/src/libs/mdb-xldap/mdbldap.c +++ b/src/libs/mdb-xldap/mdbldap.c @@ -383,7 +383,8 @@ MdbToLdap(char *MdbDn) if (obj) { if (obj == MdbDn) { *obj++ = '\0'; - base = ""; + base = malloc(MDB_MAX_OBJECT_CHARS + 1); + base[0] = '\0'; scope = LDAP_SCOPE_BASE; } else { *obj++ = '\0'; diff --git a/src/libs/python/Bongo.rules b/src/libs/python/Bongo.rules index 09f63d6..4db1d91 100644 --- a/src/libs/python/Bongo.rules +++ b/src/libs/python/Bongo.rules @@ -145,14 +145,13 @@ pkgpythonstore_PYTHON := \ src/libs/python/bongo/store/StoreConnection.py CLEANFILES += \ - src/libs/python/bongo-python-wrapper \ src/libs/python/bongo/*.pyc \ src/libs/python/bongo/external/*.pyc \ src/libs/python/bongo/external/simplejson/*.pyc \ src/libs/python/bongo/nmap/*.pyc \ src/libs/python/bongoy/store/*.pyc -src/libs/python/bongo/Xpl.py: $(top_builddir)/config.status src/libs/python/bongo/Xpl.py.in +src/libs/python/bongo/Xpl.py: $(top_builddir)/config.status $(srcdir)/src/libs/python/bongo/Xpl.py.in cd $(top_builddir) && $(SHELL) ./config.status $@ src/libs/python/bongo-python-wrapper: $(top_builddir)/config.status $(srcdir)/src/libs/python/bongo-python-wrapper.in diff --git a/src/www/bongo/dragonfly/MailView.py b/src/www/bongo/dragonfly/MailView.py index 77ea8ea..ab39d57 100644 --- a/src/www/bongo/dragonfly/MailView.py +++ b/src/www/bongo/dragonfly/MailView.py @@ -23,7 +23,8 @@ import urllib import traceback class ConversationsHandler(ResourceHandler): - pageSize = 30 + ## Default number of items shown in a mail list view. + defaultPageSize = 30 def _UpdateComposer(self, composer, jsob) : composer.SetAddressLine("From", jsob.get("from")) @@ -541,16 +542,6 @@ class ConversationsHandler(ResourceHandler): if resourceLen > 2 : rp.handlerData["attachment"] = resource.pop(0) - if not rp.handlerData.has_key("conversation") : - if rp.page is None: - start = end = -1 - else: - start = self.pageSize * (rp.page - 1) - end = start + self.pageSize - 1 - - rp.handlerData["start"] = start - rp.handlerData["end"] = end - def ParsePath(self, rp) : if (rp.resource) : self._ParseResource(rp, rp.resource.split("/")) @@ -569,9 +560,18 @@ class ConversationsHandler(ResourceHandler): elif rp.handlerData.has_key("conversation") : return self._SendJson(req, self._GetConversation(store, rp, [ 1, 1, 1, 1 ])) else : + if not rp.handlerData.has_key("conversation") : + # We have to work out what IDs to start and end on with the Mail List view. + # This involves trying to get the user's preferred pageSize, set in the DF prefs. + if rp.page is None: + start = end = -1 + else: + pageSize = self._GetPageSize(store) + start = pageSize * (rp.page - 1) + end = start + pageSize - 1 return self._SendJson (req, self._GetConversationList(store, rp, - [rp.handlerData["start"], rp.handlerData["end"], - rp.handlerData["start"], rp.handlerData["end"], + [start, end, + start, end, True])) finally : store.Quit() @@ -790,7 +790,7 @@ class ConversationsHandler(ResourceHandler): ret = {} if showTotal: ret["total"] = storeConvsIter.total - ret["pageSize"] = self.pageSize + ret["pageSize"] = self._GetPageSize(store) ret["conversations"] = convs if propsStart == -1: @@ -931,6 +931,18 @@ class ConversationsHandler(ResourceHandler): return self._SendJson(req, ret) + ## Returns the optimum number of items to show for the mail list view. + # @brief Looks at the Dragonfly preferences for a user-defined pageSize. If one exists, try to use it. If not, use self.defaultPageSize. This then defines how many mail items are shown per page in the mail list view. + # @param self The object pointer. + # @param store The store object. + # @return Number of items to show. + def _GetPageSize(self, store): + try: + prefs = self._JsonToObj(store.Read("/preferences/dragonfly")) + return int(prefs['mail']['pageSize']) + except: + return self.defaultPageSize + class ContactsHandler(ConversationsHandler): groupSize = 8 def ParsePath (self, rp) : diff --git a/src/www/bongo/dragonfly/Server.py b/src/www/bongo/dragonfly/Server.py index 83f0d17..e5761d2 100644 --- a/src/www/bongo/dragonfly/Server.py +++ b/src/www/bongo/dragonfly/Server.py @@ -1,7 +1,7 @@ from mod_python import apache, util from bongo.commonweb.ApacheLogHandler import ApacheLogHandler, RequestLogProxy from ResourcePath import ResourcePath -from HttpError import HttpError +from bongo.commonweb.HttpError import HttpError import Auth import bongo.commonweb.BongoFieldStorage diff --git a/src/www/js/AddressBook.js b/src/www/js/AddressBook.js index 3a96768..fa19b0b 100644 --- a/src/www/js/AddressBook.js +++ b/src/www/js/AddressBook.js @@ -280,83 +280,6 @@ Dragonfly.AddressBook.ContactPicker.prototype.newContactHandler = function (evt) this.popup.edit (evt, contact, this.newContactId); }; -// The FakeFriendPopup manages the interaction for unknown contacts. -Dragonfly.AddressBook.FakeFriendPopup = function (elem) -{ - Dragonfly.PopupBuble.apply (this, arguments); -}; - -Dragonfly.AddressBook.FakeFriendPopup.prototype = clone (Dragonfly.PopupBuble.prototype) -Dragonfly.AddressBook.FakeFriendPopup.prototype.dispose = -Dragonfly.AddressBook.FakeFriendPopup.prototype.disposeZone = function () -{ - this.hide(); - delete this.contact; - delete this.formNames; -}; - -Dragonfly.AddressBook.FakeFriendPopup.prototype.summarize = function (contact, elem) -{ - var d = Dragonfly; - - this.hide (); - this.setClosable (true); - this.contact = contact = (contact) ? contact : this.contact; - - var editId = d.nextId ('person-add'); - - var html = new d.HtmlBuilder(); - html.push ('

' + contact.fn + ''); - html.push (''); - html.push ('
'); - - var loc = new d.Location ({ tab: 'mail', set:'all', handler:'contacts', - contact: contact.bongoId }); - html.push ('

'); - html.set (this.contentId); - - Event.observe (editId, 'click', this.add.bindAsEventListener (this)); - this.showVertical (elem); -} - -Dragonfly.AddressBook.FakeFriendPopup.prototype.add = function () -{ - var AB = Dragonfly.AddressBook; - this.serializeContact(); - this.elem.innerHTML = this.contact.fn; - - Dragonfly.notify (_('Saving changes...'), true); - AB.saveContact (this.contact).addCallbacks (bind ( - function (result) { - // update preferences with contact ID - if (this.setMyContact) { - var id = (this.myId == '') ? result.bongoId : this.myId; - AB.Preferences.setMyContactId (id); - } - - // Create sidebox element if this is a new contact - if (result.bongoId) { - this.contact.bongoId = result.bongoId; - this.setElem (AB.sideboxPicker.addItem (this.contact.fn, result.bongoId)); - $(this.elem).scrollIntoView(); - } - - Dragonfly.notify (_('Changes saved.')); - this.summarize (); - this.shouldAutohide = true; - callLater (2, bind ('autohide', this)); - return result; - }, this), bind ('showError', this)); -}; - // The ContactPopup manages the interaction for creating and editing contacts Dragonfly.AddressBook.ContactPopup = function (elem) { @@ -482,14 +405,14 @@ Dragonfly.AddressBook.ContactPopup.prototype.loadContact = function () var form = $(this.formId); form.fn.value = this.contact.fn; - var myId = AB.Preferences.getMyContactId(); + //var myId = AB.Preferences.getMyContactId(); - logDebug('myID: ' + myId); + //logDebug('myID: ' + myId); logDebug('form id: ' + form); logDebug('this.contact: ' + this.contact); logDebug('this.contact.fn: ' + this.contact.fn); - form.isMyContact.checked = myId && (myId == this.contact.bongoId); + //form.isMyContact.checked = myId && (myId == this.contact.bongoId); for (var i = 0; i < Fields.props.length; i++) { var prop = Fields.props[i]; @@ -515,13 +438,13 @@ Dragonfly.AddressBook.ContactPopup.prototype.serializeContact = function () var form = $(this.formId); contact.fn = form.fn.value; - if (form.isMyContact.checked) { + /*if (form.isMyContact.checked) { this.setMyContact = true; this.myId = this.contact.bongoId || ''; } else if (this.contact.bongoId == AB.Preferences.getMyContactId()) { this.setMyContact = true; this.myId = null; - } + }*/ // clear out existing properties forEach (props, function (prop) { delete contact[prop]; }); @@ -602,8 +525,7 @@ Dragonfly.AddressBook.ContactPopup.prototype.edit = function (evt, contact, elem var form = [ '

', notebook, '
']; + 'src="img/contact-unknown.png">

', notebook, '']; var actions = [{ value: _('Cancel'), onclick: 'dispose'}, { value: _('Save'), onclick: 'save'}]; if (this.contact.bongoId) { // only add delete for pre-existing contacts @@ -642,10 +564,10 @@ Dragonfly.AddressBook.ContactPopup.prototype.save = function () AB.saveContact (this.contact).addCallbacks (bind ( function (result) { // update preferences with contact ID - if (this.setMyContact) { + /*if (this.setMyContact) { var id = (this.myId == '') ? result.bongoId : this.myId; AB.Preferences.setMyContactId (id); - } + }*/ // Create sidebox element if this is a new contact if (result.bongoId) { @@ -666,6 +588,7 @@ Dragonfly.AddressBook.ContactPopup.prototype.save = function () Dragonfly.AddressBook.ContactPopup.prototype.delConfirm = function () { + var d = Dragonfly; this.hide(); var text = [ '

', d.format(_('Are you sure you want to delete the contact "{0}"? This cannot be undone.'), @@ -677,3 +600,154 @@ Dragonfly.AddressBook.ContactPopup.prototype.delConfirm = function () this.show(); }; +Dragonfly.AddressBook.UserProfile = function (elem) +{ + this.formId = elem; + this.bongoId = null; +}; + +Dragonfly.AddressBook.UserProfile.prototype = {}; + +Dragonfly.AddressBook.UserProfile.prototype.build = function (contact) +{ + var d = Dragonfly; + + this.contact = contact; + + this.formNames = { }; + + var notebook = new d.Notebook(); + for (var i = 0; i < Dragonfly.AddressBook.ContactPopup.prototype.Form.length; i++) { + var tab = d.AddressBook.ContactPopup.prototype.Form[i]; + var page = notebook.appendPage (tab.category); + this.buildTab (new d.HtmlBuilder(), tab).set(page); + } + + var html = new d.HtmlBuilder (); + html.push ('

'); + d.HtmlBuilder.buildChild(html, notebook); + + html.set(this.formId); + + //var actions = [{ value: _('Save'), onclick: 'save'}]; + //Dragonfly.Preferences.Editor.buildInterface (form, actions, this.belement); + + if (this.contact != null) + { + this.loadContact(); + } +}; + +Dragonfly.AddressBook.UserProfile.prototype.loadContact = function () +{ + var AB = Dragonfly.AddressBook; + var Fields = AB.ContactPopup.prototype.FieldTypes; + + var form = $(this.formId); + form.fn.value = this.contact.fn; + + //logDebug('myID: ' + myId); + + //form.isMyContact.checked = myId && (myId == this.contact.bongoId); + + for (var i = 0; i < Fields.props.length; i++) { + var prop = Fields.props[i]; + var values = this.contact[prop]; + if (!values) { + continue; + } + for (var j = 0; j < values.length; j++) { + var value = values[j]; + var input = this.getFreeField (AB.ContactPopup.prototype.getName (prop, value.type), false); + if (input) { + input.value = $V(value); + } + } + } +}; + +Dragonfly.AddressBook.UserProfile.prototype.getFreeField = function (name, asString) +{ + if (asString) { + var n = this.formNames[name]; + n = (n == undefined) ? 0 : n + 1; + this.formNames[name] = n; + return name + String (n); + } + return $(this.formId)[name+'0']; +}; + +Dragonfly.AddressBook.UserProfile.prototype.buildTab = function (html, tab) +{ + var fields = tab.fields; + var formFields = this.formFields; + + html.push ('
    '); + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + + var name = Dragonfly.AddressBook.ContactPopup.prototype.getName (field.prop, [tab.type, field.type]); + name = this.getFreeField (name, true); + html.push ('
  • '); + if (field.longtext) { + html.push (''); + } else { + html.push (''); + } + html.push ('
  • '); + } + html.push ('
'); + return html; +}; + +Dragonfly.AddressBook.UserProfile.prototype.save = function () +{ + var AB = Dragonfly.AddressBook; + this.name = this.contact.fn; + this.serializeContact(); + //this.elem.innerHTML = this.contact.fn; + + AB.saveContact (this.contact).addCallbacks (bind ( + function (result) { + // update preferences with contact ID + if (result.bongoId) + { + this.bongoId = result.bongoId; + } + else + { + this.bongoId = AB.Preferences.getMyContactId(); + } + + return result; + }, this)); +}; + +Dragonfly.AddressBook.UserProfile.prototype.serializeContact = function () +{ + var AB = Dragonfly.AddressBook; + var props = AB.ContactPopup.prototype.FieldTypes.props; + var contact = this.contact; + var form = $(this.formId); + contact.fn = form.fn.value; + + // clear out existing properties + forEach (props, function (prop) { delete contact[prop]; }); + + for (var name in this.formNames) { // for each type of field + var count = this.formNames[name]; + var components = name.split ('-'); + var prop = components[0]; + var types = components.slice(1); + + for (var i = 0; i <= count; i++) { // for each field + var value = form[name+String(i)].value; + if (value && value != '') { + var proparray = contact[prop] || [ ]; + proparray.push ({value:value, type:types}); + contact[prop] = proparray; + } + } + } +}; diff --git a/src/www/js/BongoCalendar.js b/src/www/js/BongoCalendar.js index cdb5901..166795b 100644 --- a/src/www/js/BongoCalendar.js +++ b/src/www/js/BongoCalendar.js @@ -65,17 +65,11 @@ Dragonfly.Calendar.BongoCalendar.prototype.parseJSON = function (jsob) { var d = Dragonfly; - // TODO: This is really nasty. function calColor (calname) { return { 'Personal': 'blue', - 'Red Sox': 'red', - 'US Holidays': 'orange', 'Holidays': 'orange', - 'The Moon': 'gray', - 'Novell': 'red', - 'openSUSE': 'green', 'Meetings': 'brown' }[calname] || d.getRandomColor(); } @@ -95,7 +89,6 @@ Dragonfly.Calendar.BongoCalendar.prototype.parseJSON = function (jsob) this.subscriptionUrl = "/user/" + d.userName + "/calendar/" + d.escapeHTML(this.cal.name) + "/events"; - /* // this should probably trust the server... switch (this.type) { case 'personal': @@ -112,7 +105,6 @@ Dragonfly.Calendar.BongoCalendar.prototype.parseJSON = function (jsob) this.cal.username = jsob.username; break; } - */ }; Dragonfly.Calendar.BongoCalendar.prototype.refresh = function () diff --git a/src/www/js/CalendarEditor.js b/src/www/js/CalendarEditor.js index 22b9474..96befe7 100644 --- a/src/www/js/CalendarEditor.js +++ b/src/www/js/CalendarEditor.js @@ -1038,7 +1038,7 @@ Dragonfly.Calendar.CalendarInvitationPopup.prototype.deleteClicked = function (e var d = Dragonfly; var loc = new d.Location ({ tab: 'mail', conversation: this.invite.convId, message: this.invite.bongoId }); - d.notify (_('genericSavingChanges'), true); + d.notify (_('Saving changes...'), true); d.request ('POST', loc, { method: 'delete' }).addCallbacks ( bind ('disposeAndReload', this), bind ('showError', this)); @@ -1049,7 +1049,7 @@ Dragonfly.Calendar.CalendarInvitationPopup.prototype.junkClicked = function (evt var d = Dragonfly; var loc = new d.Location ({ tab: 'mail', conversation: this.invite.convId, message: this.invite.bongoId }); - d.notify (_('genericSavingChanges'), true); + d.notify (_('Saving changes...'), true); d.request ('POST', loc, { method: 'junk' }).addCallbacks ( bind ('disposeAndReload', this), bind ('showError', this)); @@ -1059,7 +1059,7 @@ Dragonfly.Calendar.CalendarInvitationPopup.prototype.ignoreClicked = function (e { var d = Dragonfly; var loc = new d.Location ({ tab: 'mail', conversation: this.invite.convId, message: this.invite.bongoId }); - d.notify (_('genericSavingChanges'), true); + d.notify (_('Saving changes...'), true); var req = d.request ('POST', loc, { method: 'archive' }).addCallbacks ( bind ('disposeAndReload', this), bind ('showError', this)); diff --git a/src/www/js/Composer.js b/src/www/js/Composer.js index d2af4a8..d6a4019 100644 --- a/src/www/js/Composer.js +++ b/src/www/js/Composer.js @@ -130,7 +130,7 @@ Dragonfly.Mail.Composer.prototype.buildHtml = function (html) '', '
', - '', _('Subject:'), '', + '', _('Subject:'), '', '', _('From:'), '', d.escapeHTML (this.msg.from), '', '', _('Attachments:'), '
    '); @@ -154,7 +154,7 @@ Dragonfly.Mail.Composer.prototype.buildHtml = function (html) } } - html.push ('
  • ', _('mailAttachLabel'), '
', + html.push ('
  • ', _('Attach file...'), '
  • ', '', '', @@ -284,9 +284,13 @@ Dragonfly.Mail.Composer.prototype.saveDraft = function (evt, msg) return false; } - //msg = msg || this.getCurrentMessage (); - msg = this.getCurrentMessage(); - + msg = msg; + if (!msg || !msg.from) + { + logDebug('Arg passed was an event, not a real message.'); + msg = this.getCurrentMessage(); + } + if (!this.hasChanges (msg)) { logDebug ('No changes to save'); return true; @@ -302,6 +306,13 @@ Dragonfly.Mail.Composer.prototype.saveDraft = function (evt, msg) conversation: this.conversation, message: this.bongoId }; + + /*if (!msg.subject) + { + var untitled = _('Untitled'); + this.subject = untitled; + msg.subject = untitled + }*/ loc = new d.Location (loc); this.def = d.requestJSONRPC ((this.draftSavedAlready ? 'update' : 'create') + 'Draft', loc, @@ -310,23 +321,12 @@ Dragonfly.Mail.Composer.prototype.saveDraft = function (evt, msg) this.forward || null, this.calendarInvitationFor || null, this.useAuthUrls || false); - - var displaysubject = ''; - if (msg.subject) - { - displaysubject = d.escapeHTML (msg.subject); - } - else - { - msg.subject = _('Untitled'); - displaysubject = d.escapeHTML (msg.subject); - } - d.notify (d.format (_('Saving draft "{0}"...'), displaysubject), true); + d.notify (d.format (_('Saving draft "{0}"...'), d.escapeHTML (msg.subject)), true); return this.def.addCallbacks ( bind (function (jsob) { - d.notify (_('Saved draft') + ' "' + displaysubject + '".'); + d.notify (_('Saved draft') + ' "' + d.escapeHTML (msg.subject) + '".'); this.draftSavedAlready = true; this.lastSavedMsg = msg; diff --git a/src/www/js/Dragonfly.js b/src/www/js/Dragonfly.js index ba217ca..774162f 100644 --- a/src/www/js/Dragonfly.js +++ b/src/www/js/Dragonfly.js @@ -1,6 +1,6 @@ Dragonfly = { title: 'Bongo', - version: 'SVN r2483+', + version: 'M3', userName: '', tabs: { }, NAME: 'Dragonfly' @@ -342,11 +342,13 @@ Dragonfly.go = function (path) } d.contentIFrameZone.disposeZone(); - //logDebug (startDate + ': Loading ', path, ':', serializeJSON (loc)); - //logDebug (' from: ', d.currentView); - //logDebug (' location: ', window.location); - //logDebug (' hash: ', window.location.hash); - //logDebug (' loc: ', serializeJSON(loc)); + /*logDebug (startDate + ': Loading ', path, ':', serializeJSON (loc)); + logDebug (' from: ', d.currentView); + logDebug (' location: ', window.location); + logDebug (' hash: ', window.location.hash); + logDebug (' loc: ', serializeJSON(loc));*/ + + logDebug('curLoc: ', loc); if (!loc || !loc.valid) { logError ('invalid path: ' + path); @@ -368,10 +370,22 @@ Dragonfly.go = function (path) } prof.toggle ('request'); + logDebug('checking if ' + loc.handler + ' contains function getData(loc)...'); if (h.getData) { + logDebug('Yup!'); self.def = h.getData (loc); } else { - self.def = d.requestJSON ('GET', loc); + logDebug('Nope! Checking if ' + loc.tab + ' contains function getData(loc)...'); + if (v.getData) + { + logDebug('Yup!'); + self.def = v.getData(loc); + } + else + { + logDebug('Nope!'); + self.def = d.requestJSON ('GET', loc); + } } self.def.loc = loc; @@ -923,16 +937,13 @@ Dragonfly.start = function () d.translateElements(); d.setLoginMessage (_('Logged in: loading contacts and calendars...')); - - // setup the preferences dialog tabs - //d.setupPrefs(); - + // set current timezone to default and build timezone selector d.curTzid = c.Preferences.getDefaultTimezone(); - //d.tzselector = new d.TzSelector (d.curTzid, 'tzselect', true); - //d.tzselector.setChangeListener (function () { d.setCurrentTzid (d.tzselector.getTzid()); }); - var def = new d.MultiDeferred ([ c.loadCalendars(), + /*var def = new d.MultiDeferred ([ c.loadCalendars(), + d.AddressBook.sideboxPicker.load() ]);*/ + var def = new DeferredList ([ c.loadCalendars(), d.AddressBook.sideboxPicker.load() ]); return def.addCallbacks ( function (res) { @@ -950,9 +961,13 @@ Dragonfly.start = function () $('login-user').value = ''; $('login-password').value = ''; Element.setText ('user-name', d.userName); - Element.setHTML ('logout-text', _('Log out') + ' ' + d.userName); + Element.setHTML ('logout-text', d.format(_('Log out {0}...'), d.userName)); + Dragonfly.logoutMessage = _('You have logged out successfully.'); showElement ('content'); + // Listen for clicks to main content thing, so we can hide popups. + Event.observe ('content', 'click', Dragonfly.hidePopups.bindAsEventListener(this)); + // Add administration link if we're admin if (d.userName == 'admin') { @@ -1016,6 +1031,20 @@ Dragonfly.initHtmlZones = function () Event.observe (window, 'unload', bind ('disposeZone', d.contentZone)); }; +Dragonfly.hidePopups = function () +{ + if (Dragonfly.lastPopup) + { + Dragonfly.lastPopup.dispose(); + logDebug('Attempted popup dispose complete.'); + Dragonfly.lastPopup = null; + } + else + { + logDebug('Nothing to dispose'); + } +} + Dragonfly.main = function () { Dragonfly.browserDetect(); diff --git a/src/www/js/Login.js b/src/www/js/Login.js index bd0a37c..b1e1088 100644 --- a/src/www/js/Login.js +++ b/src/www/js/Login.js @@ -110,7 +110,6 @@ Dragonfly.translateLogin = function () Element.setHTML ('login-language-label', _('Language')); Element.setHTML ('login-default-label', _('Remember me')); $('login-button').value = _('Login'); - Dragonfly.logoutMessage = _('You have logged out successfully.'); }; Dragonfly.languageSuccess = function () @@ -193,6 +192,7 @@ Dragonfly.showLoginPane = function () if (location.hash == '#LoggedOut') { Dragonfly.setLoginMessage (Dragonfly.logoutMessage); + Dragonfly.langFaliure = true; // Stops us from removing the 'You have logged out' message when we load the lang. location.hash = (Dragonfly.isWebkit) ? '' : '#'; $('login-user').focus(); } else { diff --git a/src/www/js/Mail.js b/src/www/js/Mail.js index c5bf5fd..ca36922 100644 --- a/src/www/js/Mail.js +++ b/src/www/js/Mail.js @@ -8,15 +8,34 @@ Dragonfly.tabs['mail'] = Dragonfly.Mail; Dragonfly.Mail.handlers = { }; Dragonfly.Mail.sets = [ 'all', 'inbox', 'starred', 'sent', 'drafts', 'trash', 'junk' ]; Dragonfly.Mail.setLabels = { - 'all': 'All', - 'inbox': 'Inbox', - 'starred': 'Starred', - 'sent': 'Sent', - 'drafts': 'Drafts', - 'trash': 'Trash', - 'junk': 'Junk' + 'all': N_('All'), + 'inbox': N_('Inbox'), + 'starred': N_('Starred'), + 'sent': N_('Sent'), + 'drafts': N_('Drafts'), + 'trash': N_('Trash'), + 'junk': N_('Junk') }; +Dragonfly.Mail.getData = function (loc) +{ + logDebug('Dragonfly.Mail.getData(loc) called.'); + var d = Dragonfly; + var m = d.Mail; + + var view = m.getView(loc); + if (view.getData) + { + logDebug('loc ', loc, ' has a getView function.'); + return view.getData(loc); + } + else + { + logDebug('No getView function - falling back to requestJSON.'); + return d.requestJSON ('GET', loc); + } +} + Dragonfly.Mail.getView = function (loc) { logDebug('Dragonfly.Mail.getView(loc) called.'); @@ -82,8 +101,11 @@ Dragonfly.Mail.Preferences.getFromAddress = function () { var d = Dragonfly; var p = d.Preferences; - - return p.prefs.mail.from; + + var emailfrom = p.prefs.mail.from; + var namefrom = p.prefs.mail.sender; + + return d.format("{0} <{1}>", namefrom, emailfrom); }; Dragonfly.Mail.Preferences.setFromAddress = function (address) @@ -411,7 +433,7 @@ Dragonfly.Mail.joinParticipants = function (parts) }, parts).join (', '); }; -Dragonfly.Mail.Conversations = { label: 'Conversations' }; +Dragonfly.Mail.Conversations = { label: N_('Conversations') }; Dragonfly.Mail.handlers['conversations'] = Dragonfly.Mail.Conversations; Dragonfly.Mail.Conversations.parseArgs = function (loc, args) @@ -561,7 +583,7 @@ Dragonfly.Mail.Messages.load = function (loc, jsob) }; */ -Dragonfly.Mail.Contacts = { label: 'Contacts' }; +Dragonfly.Mail.Contacts = { label: N_('Contacts') }; Dragonfly.Mail.handlers['contacts'] = Dragonfly.Mail.Contacts; Dragonfly.Mail.Contacts.parseArgs = function (loc, args) @@ -664,7 +686,7 @@ Dragonfly.Mail.Contacts.getBreadCrumbs = function (loc) } }; -Dragonfly.Mail.Subscriptions = { label: 'Mailing Lists' }; +Dragonfly.Mail.Subscriptions = { label: N_('Mailing Lists') }; Dragonfly.Mail.handlers['subscriptions'] = Dragonfly.Mail.Subscriptions; Dragonfly.Mail.Subscriptions.parseArgs = function (loc, args) @@ -777,7 +799,7 @@ Dragonfly.Mail.Subscriptions.getBreadCrumbs = function (loc) } }; -Dragonfly.Mail.ToMe = { label: 'To Me' }; +Dragonfly.Mail.ToMe = { label: N_('To Me') }; Dragonfly.Mail.handlers['tome'] = Dragonfly.Mail.ToMe; Dragonfly.Mail.ToMe.parseArgs = function (loc, args) @@ -855,3 +877,66 @@ Dragonfly.Mail.ToMe.load = function (loc, jsob) return v.load (loc, jsob); }; + +Dragonfly.Mail.yeahBaby = function (msg) +{ + var d = Dragonfly; + + if (!d.Preferences.prefs.mail.colorQuotes) + { + return d.htmlizeText (msg); + } + + // Split the message up by newlines. + msg = msg.split("\n"); + + var colors = new Array(); + + // Loop through and find quotes. + for (i=0;i + if (msg[i].substring(0, 1) == ">") + { + // Loop and find out how deep we are. + var depth = 0; + for (x=0;x') + { + depth++; + } + } + + var color = ''; + if (colors.length < depth) + { + color = d.getRandomColor(); + + // Make sure the color isn't the same as parent quote. + if (colors.length > 0) + { + while (color == colors[depth - 1]) + { + color = d.getRandomColor(); + } + } + + // Push it onto the array to get later if needed. + colors.push(color); + } + else + { + color = colors[depth - 1]; + } + + msg[i] = '' + d.htmlizeText (msg[i]) + ''; + } + else + { + msg[i] = d.htmlizeText (msg[i]); + } + } + + return msg.join("
    "); +} diff --git a/src/www/js/MailConversationView.js b/src/www/js/MailConversationView.js index 1dc04e2..f41885e 100644 --- a/src/www/js/MailConversationView.js +++ b/src/www/js/MailConversationView.js @@ -40,7 +40,7 @@ Dragonfly.Mail.ConversationView.selectAlternative = function (part) { var favorite = null; - //logDebug('checking alternatives'); + logDebug('checking alternatives'); for (var i = 0; i < part.children.length; i++) { var child = part.children[i]; if (child.preview && (child.previewtype == 'text/plain' @@ -63,7 +63,16 @@ Dragonfly.Mail.ConversationView.formatPart = function (loc, msg, part) if (part.preview) { html.push ('
    '); if (part.previewtype == 'text/plain') { - html.push (d.htmlizeText (part.preview)); + html.push ('
    '); + if (d.Preferences.prefs.mail.colorQuotes) + { + html.push (m.yeahBaby (part.preview)); + } + else + { + html.push (d.htmlizeText (part.preview)); + } + html.push ('
    '); } else if (part.previewtype == 'text/html') { html.push (d.linkifyHtml (part.preview)); } else { @@ -91,7 +100,7 @@ Dragonfly.Mail.ConversationView.formatPart = function (loc, msg, part) html.push (v.formatPart(loc, msg, child)); } else { if (!inAttachments) { - html.push ('
    Attachments:
      '); + html.push ('
      ', _('Attachments:'), '
        '); inAttachments = 1; } var partLoc = new d.Location (loc); diff --git a/src/www/js/MailListView.js b/src/www/js/MailListView.js index 34f389b..a2d55b6 100644 --- a/src/www/js/MailListView.js +++ b/src/www/js/MailListView.js @@ -73,6 +73,7 @@ Dragonfly.Mail.ListView.load = function (loc, jsob) var force = false; var html = new d.HtmlBuilder ('
        '); + var pageSize = m.Preferences.getPageSize (); document.title = _(loc.set) + ' - ' + _(loc.tab) + ': ' + Dragonfly.title; @@ -104,7 +105,7 @@ Dragonfly.Mail.ListView.load = function (loc, jsob) list.buildEnd (html); new d.Pager (html, pageFmt, - loc.page, Math.ceil (jsob.total / jsob.pageSize)); + loc.page, Math.ceil (jsob.total / pageSize)); html.push ('
        '); html.set ('content-iframe'); @@ -137,7 +138,7 @@ Dragonfly.Mail.MultiListView.getData = function (loc) var m = d.Mail; var pageSize = m.Preferences.getPageSize (); - + var propsStart = ((loc.page || 1) - 1) * pageSize; return d.requestJSONRPC ('getConversationList', loc, @@ -160,6 +161,7 @@ Dragonfly.Mail.MultiListView.load = function (loc, jsob) loc = new d.Location (loc); var html = new d.HtmlBuilder ('
        '); + var pageSize = m.Preferences.getPageSize (); document.title = _(loc.set) + ' - ' + _(loc.tab) + ': ' + Dragonfly.title; @@ -199,7 +201,7 @@ Dragonfly.Mail.MultiListView.load = function (loc, jsob) pageFmt = loc.getClientUrl ('handler') + '/page{0}'; - new d.Pager (html, pageFmt, loc.page, Math.ceil (jsob.total / jsob.pageSize)); + new d.Pager (html, pageFmt, loc.page, Math.ceil (jsob.total / pageSize)); html.push ('
        '); html.set ('content-iframe'); diff --git a/src/www/js/OccurrenceEditor.js b/src/www/js/OccurrenceEditor.js index 3301f67..ca0d89f 100644 --- a/src/www/js/OccurrenceEditor.js +++ b/src/www/js/OccurrenceEditor.js @@ -124,9 +124,16 @@ Dragonfly.Calendar.OccurrencePopup.prototype.edit = function (evt, occurrence, e this.setClosable (false); delete this.changes; // may be set if we're editing after a save but before dispose if (occurrence) { - this.occurrence = (typeof occurrence == 'string') - ? d.JCal.buildNewEvent (occurrence).occurrences[0] - : occurrence; + if (!occurrence.pageX) + { + this.occurrence = (typeof occurrence == 'string') + ? d.JCal.buildNewEvent (occurrence).occurrences[0] + : occurrence; + } + else + { + // Rebuild the event? + } } else if (!this.occurrence) { this.occurrence = d.JCal.buildNewEvent ().occurrences[0]; } @@ -277,7 +284,7 @@ Dragonfly.Calendar.OccurrencePopup.prototype.getScope = function (forSave) '', '']; var actions = [ - { value: _('genericCancel'), onclick: 'dispose'}, + { value: _('Cancel'), onclick: 'dispose'}, { value: forSave ? _('Save') : _('Delete'), onclick: partial (this.dispatchWithScope, forSave) }]; this.setForm (form, actions); this.show(); @@ -377,7 +384,7 @@ Dragonfly.Calendar.OccurrenceEditor.prototype.buildSharingTab = function (page) var c = d.Calendar; var html = new d.HtmlBuilder ( - _('includeEventLabel'), + _('Include this event in:'), '
          '); var calIds = this.occurrence.vcalendar.calendarIds; diff --git a/src/www/js/Preferences.js b/src/www/js/Preferences.js index 7fab1b5..f6fdcda 100644 --- a/src/www/js/Preferences.js +++ b/src/www/js/Preferences.js @@ -32,6 +32,9 @@ Dragonfly.Preferences.defaultPrefs = { addressbook: { me: null }, + mail: { + colorQuotes: true + }, calendar: { dayStart: 7, defaultView: 'month', @@ -238,79 +241,90 @@ Dragonfly.Preferences.Editor.parsePath = function (loc, path) Dragonfly.Preferences.Editor.build = function (loc) { var d = Dragonfly; - var showmethemoney = true; Element.setHTML ('toolbar', ''); Element.hide ('toolbar'); var html = new d.HtmlBuilder (); + // First, build the container. + html.push ('
          ', '
          '); + html.set ('content-iframe'); - if (!showmethemoney) - { - // Push the following HTML if we haven't completed our handler! - html.push ('
          ', '', - '', - '', - '

          The Preferences editor goes here! :)

          '); - - html.set ('content-iframe'); - } - else - { - // First, build the container. - html.push ('
          ', '
          '); - html.set ('content-iframe'); - - // Come up with some magic tabs! - var notebook = new d.Notebook(); - var userpage = notebook.appendPage('About Me'); - var composerpage = notebook.appendPage('Mail'); - var calendarpage = notebook.appendPage('Calendar'); - - var userhtml = new d.HtmlBuilder (); - userhtml.push ('', - '', - '', - '', - '', - '
          '); - userhtml.set (userpage); - - var composerhtml = new d.HtmlBuilder (); - composerhtml.push ('', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '
          Please don\'t abuse the above feature for now.

          ', - '', - '
          ', _('items'), '
          '); - composerhtml.set (composerpage); - - var calendarhtml = new d.HtmlBuilder (); - calendarhtml.push ('

          Nothing to see here, move along.

          '); - calendarhtml.set (calendarpage); - - var form = [ - '
          ', notebook, '
          ']; - - var actions = [{ value: _('Cancel'), onclick: 'dispose'}, { value: _('Save'), onclick: 'save'}]; - - // Now, fill in the content with tabs & buttons. - this.contentId = 'preferences-container'; - this.buildInterface (form, actions); - logDebug('Created UI OK - setting up TzSelector widget...'); - - // Setup timezone widget - d.tzselector = new d.TzSelector (d.curTzid, 'tzpicker', true); - } + // Come up with some magic tabs! + var notebook = new d.Notebook(); + var userpage = notebook.appendPage('General'); + var mailpage = notebook.appendPage('Mail'); + var calendarpage = notebook.appendPage('Calendar'); + var composerpage = notebook.appendPage('Composer'); + + var userhtml = new d.HtmlBuilder (); + userhtml.push ('', + '', + '', + '', + '
          ', '
          '); + userhtml.set (userpage); + + var mailhtml = new d.HtmlBuilder (); + mailhtml.push ('', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '
          Please don\'t abuse the above feature for now.

          ', + '', + '
          ', _('items'), '
          '); + mailhtml.set (mailpage); + + var calendarhtml = new d.HtmlBuilder (); + calendarhtml.push ('', + '', + '', + '', + ' ', + '', + '', +// '', +// '', + '
          '); + calendarhtml.set (calendarpage); + + var composerhtml = new d.HtmlBuilder(); + composerhtml.push('', + '', + '', + '', + '', + '
          '); + composerhtml.set(composerpage); + + var form = [ + '
          ', notebook, '
          ']; + + var actions = [{ value: _('Cancel'), onclick: 'dispose'}, { value: _('Save'), onclick: 'save'}]; + + // Now, fill in the content with tabs & buttons. + this.buildInterface (form, actions, 'preferences-container'); + logDebug('Created UI OK - setting up TzSelector widget...'); + + // Setup timezone widget + d.tzselector = new d.TzSelector (d.curTzid, 'tzpicker', true); logDebug('We just got built.'); }; @@ -321,17 +335,36 @@ Dragonfly.Preferences.Editor.save = function () var d = Dragonfly; var p = d.Preferences; + // User profile + Dragonfly.notify (_('Saving changes...'), true); + var result = this.profileEditor.save(); + p.prefs.addressbook.me = this.profileEditor.bongoId; + p.prefs.mail.sender = this.profileEditor.name; + // Timezone d.setCurrentTzid (d.tzselector.getTzid()); // Mail prefs p.prefs.mail.from = $('from').value; p.prefs.mail.autoBcc = $('autobcc').value; + p.prefs.mail.pageSize = $('mailpagesize').value; p.prefs.mail.signature = $('signature').value; p.prefs.mail.usesig = $('usesig').checked; + p.prefs.mail.colorQuotes = $('colorquotes').checked; + + // Calendar prefs + p.prefs.calendar.defaultView = $('defaultcalview').value; + p.prefs.calendar.dayStart = 7; // Yes, hardwire this one (for now)! + p.prefs.calendar.sharePublicDefault = $('calshareyes').checked; + + // Composer prefs + p.prefs.composer = {}; + p.prefs.composer.messageType = $('defaultcompose'); + p.prefs.composer.lineWidth = $('linewidth'); // Finish up p.save(); + Dragonfly.notify (_('Changes saved.')); this.dispose(); }; @@ -350,17 +383,49 @@ Dragonfly.Preferences.Editor.load = function (loc, jsob) document.title = 'Preferences: ' + Dragonfly.title; // Mail prefs - $('from').value = jsob.mail.from; + if (jsob.mail && jsob.mail.from) + { + $('from').value = jsob.mail.from; + } + else + { + logWarning('You have no prefs. I should probably warn you, or.. something.'); + } - if (jsob.mail.autoBcc) { $('autobcc').value = jsob.mail.autoBcc; } - if (jsob.mail.pageSize) { $('mailpagesize').value = jsob.mail.pageSize; } - if (jsob.mail.signature) { $('signature').value = jsob.mail.signature; } - if (jsob.mail.usesig) { $('usesig').checked = jsob.mail.usesig; } + if (jsob.mail && jsob.mail.autoBcc) { $('autobcc').value = jsob.mail.autoBcc; } + if (jsob.mail && jsob.mail.pageSize) { $('mailpagesize').value = jsob.mail.pageSize; } + if (jsob.mail && jsob.mail.signature) { $('signature').value = jsob.mail.signature; } + if (jsob.mail && jsob.mail.usesig) { $('usesig').checked = jsob.mail.usesig; } + if (jsob.mail && jsob.mail.colorQuotes) { $('colorquotes').checked = jsob.mail.colorQuotes; } + + // Calendar prefs + if (jsob.calendar && jsob.calendar.defaultView) { $('defaultcalview').value = jsob.calendar.defaultView; } + if (jsob.calendar && jsob.calendar.sharePublicDefault) { $('calshareyes').checked = jsob.calendar.sharePublicDefault; $('calshareno').checked = !jsob.calendar.sharePublicDefault } else { $('calshareno').checked = true; } + //if (jsob.calendar.dayStart) { $('daystart').value = jsob.calendar.dayStart; } + + // Composer prefs + if (jsob.composer && jsob.composer.messageType) { $('defaultcompose').value = jsob.composer.messageType; } + if (jsob.composer && jsob.composer.lineWidth) { $('linewidth').value = jsob.composer.lineWidth ; } else { $('linewidth').value = '80'; } + // Now, load up the profile editor! + var pe = new d.AddressBook.UserProfile('userprofile'); + if (jsob.addressbook.me && jsob.addressbook.me != null) + { + // We've already setup our profile - load it! + d.AddressBook.loadContact(jsob.addressbook.me).addCallback(bind ('build', pe)); + } + else + { + // Build empty profile editor UI. + pe.build(Dragonfly.AddressBook.buildNewContact()); + } + + this.profileEditor = pe; + logDebug('We just loaded.'); }; -Dragonfly.Preferences.Editor.buildInterface = function (children, actions, observer) +Dragonfly.Preferences.Editor.buildInterface = function (children, actions, element) { var d = Dragonfly; @@ -375,11 +440,11 @@ Dragonfly.Preferences.Editor.buildInterface = function (children, actions, obser } html.push ('
      '); - html.set (this.contentId); + html.set (element); for (var i = 0; i < actions.length; i++){ logDebug('Setting up actions for ' + actions[i].value); var clickHandler = actions[i].onclick; - Event.observe (ids[i], 'click', bind (clickHandler, observer || this)); + Event.observe (ids[i], 'click', bind (clickHandler, this)); logDebug('Done!'); } }; diff --git a/src/www/js/Summary.js b/src/www/js/Summary.js index 011d9f0..2bc73db 100644 --- a/src/www/js/Summary.js +++ b/src/www/js/Summary.js @@ -325,7 +325,7 @@ Dragonfly.Summary.addCalInvites = function (loc, jsob) var cal = s.calInvites[bongoId]; html.push ('
    • ', d.escapeHTML (cal.calendarName), - ' ', _('summaryInviteFrom'), ' ', + ' ', _('from'), ' ', d.escapeHTML (cal.from[0][0]), '
    • '); } diff --git a/src/www/js/Util.js b/src/www/js/Util.js index a0946d0..d6aefdb 100644 --- a/src/www/js/Util.js +++ b/src/www/js/Util.js @@ -905,7 +905,7 @@ Dragonfly.requestJSONRPC = function (rpcMethod, url /*, ... */) return d.requestJSON ('POST', url, jsob).addCallback (d.getJsonRpcResult); }; -Dragonfly.Colors = [ 'yellow', 'orange', 'brown', 'red', 'gray', 'green', 'blue', 'indigo', 'violet' ]; +Dragonfly.Colors = [ 'brown', 'red', 'gray', 'green', 'blue', 'indigo', 'maroon', 'navy', 'olive', 'purple', 'MidnightBlue', 'DimGrey', 'DarkSlateGrey', 'teal', 'SlateBlue', 'SeaGreen', 'Sienna', 'DarkGoldenRod', 'BlueViolet' ]; Dragonfly.getRandomColor = function () { return Dragonfly.Colors[Math.floor ((Math.random() * 100) % Dragonfly.Colors.length)]; diff --git a/src/www/js/Widgets.js b/src/www/js/Widgets.js index 3f9cbc0..474f5a7 100644 --- a/src/www/js/Widgets.js +++ b/src/www/js/Widgets.js @@ -361,6 +361,7 @@ Dragonfly.PopupBuble.prototype.connectHtml = function (elem) this.dispose(); } }.bindAsEventListener(this)); + return elem; }; @@ -378,6 +379,7 @@ Dragonfly.PopupBuble.prototype.addPoppedOut = function () { if (this.elem) { addElementClass (this.elem, 'popped-out'); + //Dragonfly.lastPopup = this; } }; @@ -560,7 +562,7 @@ Dragonfly.PopupBuble.prototype.show = function (elem, position) } if (!this.elem) { return; - } + } this.addPoppedOut (); @@ -621,7 +623,7 @@ Dragonfly.PopupBuble.prototype.show = function (elem, position) } $(this.id).style.visibility = 'visible'; - + return; logDebug ('positioning summary:'); logDebug (' elemMetrics:', repr (elemMetrics));