Index: /Evidence/DColl.cc
===================================================================
--- /Evidence/DColl.cc	(revision 171)
+++ /Evidence/DColl.cc	(revision 172)
@@ -22,5 +22,6 @@
 #define SERVER_NAME "DColl"
 
-#define DATE_ROLLOVER 12 // localtime hour after which next date is used
+#define DATE_ROLLOVER 12 	// localtime hour after which next date is used
+#define MIN_HIST_SIZE 1024	// Minimum history buffer in bytes (> 3*sizeof(int) !)
 
 #include "Evidence.h"
@@ -50,4 +51,5 @@
       DimService *HistService;
 	  char *Buffer;
+	  unsigned int HistSize;
 	  int Next;
 	  double LastValue;
@@ -66,5 +68,4 @@
     DimService *LogSizeService, *DataSizeService, *DataFilename;
 	string HistDir;
-    int HistSize;
 	int SizeUpdateDelay;
 	int TimeForNextFile;
@@ -73,8 +74,10 @@
 	regex_t *RegEx;
 	double *MinChange;
+    unsigned int *HistSize;
 	
     void infoHandler();
     void commandHandler();
 	void AddService(string);
+	void RemoveService(string);
 	float FileSize(FILE *);
 	    
@@ -102,10 +105,8 @@
 
   // Request configuration data
-  char *Change = GetConfig(SERVER_NAME " minchange");
+  char *Change = GetConfig(SERVER_NAME " items");
   DataDir = GetConfig(SERVER_NAME " datadir");
   char *Logname = GetConfig(SERVER_NAME " logfile");
   SizeUpdateDelay = atoi(GetConfig(SERVER_NAME " sizeupdate"));
-  HistSize = atoi(GetConfig(SERVER_NAME " histsize"));
-  if (HistSize < 3*sizeof(int)) HistSize = 3*sizeof(int);
   HistDir = GetConfig(SERVER_NAME " histdir");
    
@@ -135,9 +136,10 @@
   }
   
-  // Allocate memory for regular expressions and minimum change values
+  // Allocate memory for regular expressions, minimum change and history size
   RegEx = new regex_t[RegExCount];
   MinChange = new double [RegExCount];
-
-  // Compile regular expressions
+  HistSize = new unsigned int [RegExCount];
+
+  // Compile regular expressions and extract minimum change and history size
   int Pos = 0;
   for (int i=0; i<RegExCount; i++) {
@@ -152,6 +154,9 @@
 	}
 	else {
-	  if ((Token=strtok(NULL, "")) != NULL) MinChange[i] = atof(Token);
+	  if ((Token=strtok(NULL, ": \t")) != NULL) MinChange[i] = atof(Token);
 	  else MinChange[i] = 0;
+  	  if ((Token=strtok(NULL, "")) != NULL) HistSize[i] = atoi(Token)*1024;
+	  else HistSize[i] = MIN_HIST_SIZE;
+	  if (HistSize[i] < MIN_HIST_SIZE) HistSize[i] = MIN_HIST_SIZE;
 	}
 	Pos += Len;
@@ -167,26 +172,8 @@
 DataHandler::~DataHandler() {
 
-  // Delete DIM subscriptions and command first so handlers and not called anymore
-  for (int i=0; i<List.size(); i++) {
-    delete List[i].DataItem;
-  }
+  // Delete all DIM subscriptions
+  while (List.size() != 0) RemoveService(List[0].DataItem->getName());
+  
   delete LogCommand;
-
-  // Save history buffers to files (replace '/' by '_')
-  State(INFO, "Writing history buffers to files");
-
-  for (int i=0; i<List.size(); i++) {
-    string Name = List[i].HistService->getName();
-	for (int j=0; j<Name.size(); j++) if (Name[j] == '/') Name[j] = '_';
-    FILE *File = fopen((HistDir + "/" + Name).c_str(), "wb");
-	if (File != NULL) {
-      fwrite(&List[i].Next, sizeof(List[i].Next), 1, File);
-      fwrite(List[i].Buffer, sizeof(char), HistSize, File);
-      fclose(File);
-	}
-	delete List[i].HistService;
-    delete[] List[i].Buffer;
-  }
-
   delete DataFilename;
   delete[] Filename;
@@ -232,12 +219,10 @@
   // If service is DIS_DNS/SERVER_LIST, subscribe to all SERVICE_LIST services
   if (strcmp(Info->getName(), "DIS_DNS/SERVER_LIST") == 0) {	
-	char *Token = strtok(Info->getString(), "@");	
+	char *Token = strtok(Info->getString(), "+-!@");	
 	while (Token != NULL) {
-  	  if (isalpha(*Token) == 0) Token++; // Name can start with +,-,!
-	  
-	  AddService(string(Token)+"/SERVICE_LIST");	  
-  	  
-	  Token = strtok(NULL, "|");
-	  Token = strtok(NULL, "|@");	// ???? Why needed ?????
+	  if (*Info->getString()=='-' || *Info->getString()=='!') RemoveService(string(Token)+"/SERVICE_LIST");	  
+	  else AddService(string(Token)+"/SERVICE_LIST");
+	  Token = strtok(NULL, "|"); // Skip server IP address
+	  Token = strtok(NULL, "@");
 	}	
 	return;
@@ -247,12 +232,13 @@
   // Subscribe to all services (but not to commands and RPCs)
   if (strstr(Info->getName(), "/SERVICE_LIST") != NULL) {
-
-	char *Name = strtok(Info->getString(), "|");
+	char *Name = strtok(Info->getString(), "+-!|");
 	while (Name != NULL) {
+	  // Check if item is a service
 	  char *Type = strtok(NULL, "\n");
 	  if (Type == NULL) return; // for safety, should not happen
-	  if (isalpha(*Name) == 0) Name++; // Name can start with +,-,!
       if (strstr(Type, "|CMD")==NULL && strstr(Type, "|RPC")==NULL) {
-		AddService(Name);
+	    // Add or remove service
+	    if (*Info->getString()=='-' || *Info->getString()=='!') RemoveService(Name);
+		else AddService(Name);
 	  }
 	  Name = strtok(NULL, "|");
@@ -323,61 +309,66 @@
   // If negative value for absolute change, do not write to file
   if (List[Service].MinAbsChange >= 0) {
-
-  // Write data header
-  time_t RawTime = Info->getTimestamp();
-  struct tm *TM = localtime(&RawTime);
-
-  fprintf(DataFile, "%s %d %d %d %d %d %d %d %lu ", Info->getName(), TM->tm_year+1900, TM->tm_mon+1, TM->tm_mday, TM->tm_hour, TM->tm_min, TM->tm_sec, Info->getTimestampMillisecs(), Info->getTimestamp());
-
-  // Translate data into ASCII
-  char *Text = EvidenceServer::ToString(Info);
-
-  if (Text != NULL) {
-	// Replace all control characters by white space
-	for (int i=0; i<strlen(Text); i++) if (iscntrl(Text[i])) Text[i] = ' ';
-	
-	// Write to file
-    fprintf(DataFile, "%s\n", Text);
-	
+	// Write data header
+	time_t RawTime = Info->getTimestamp();
+	struct tm *TM = localtime(&RawTime);
+
+	fprintf(DataFile, "%s %d %d %d %d %d %d %d %lu ", Info->getName(), TM->tm_year+1900, TM->tm_mon+1, TM->tm_mday, TM->tm_hour, TM->tm_min, TM->tm_sec, Info->getTimestampMillisecs(), Info->getTimestamp());
+
+	// Translate data into ASCII
+	char *Text = EvidenceServer::ToString(Info);
+
+	if (Text != NULL) {
+	  // Replace all control characters by white space
+	  for (int i=0; i<strlen(Text); i++) if (iscntrl(Text[i])) Text[i] = ' ';
+
+	  // Write to file
+      fprintf(DataFile, "%s\n", Text);
+
+	  free(Text);
+	}
+	else fprintf(DataFile, "Cannot interpret format identifier\n");
+
+	// Terminate if error because otherwise infinite loop might result as
+	// next call to this infoHandler() will try to (re-)open file
+	if(ferror(DataFile)) {
+      fclose(DataFile);
+	  DataFile = NULL;
+	  State(FATAL, "Error writing to data file, closed file (%s)", strerror(errno));
+	}
+
+	// Update datafile size service (not every time to avoid infinite loop)
+	if (time(NULL) - DataSizeLastUpdate > SizeUpdateDelay) {
+      fflush(DataFile); // not continuously to reduce load
+
+	  DataSizekB = FileSize(DataFile);
+	  DataSizeService->updateService();
+	  DataSizeLastUpdate = time(NULL);
+	}  
+  } // Check for disk writing
+
+  //
+  // ====== Part D: Handle history service ===
+  //
+  
+  if (Info->getSize() == 0) return;
+
+  // Check if data should be added to history buffer
+  if (strcmp(Info->getFormat(),"C") != 0 && strlen(Info->getFormat())==1) {
+	// Calculate sum of all number in array
+	char *Text = EvidenceServer::ToString(Info);
+	char *Token = strtok(Text, " ");
+	double Sum = 0;
+	while (Token != NULL) {
+	  Sum += atof(Token);
+      Token = strtok(NULL, " ");
+	}
 	free(Text);
-  }
-  else fprintf(DataFile, "Cannot interpret format identifier\n");
- 
-  // Terminate if error because otherwise infinite loop might result as
-  // next call to this infoHandler() will try to (re-)open file
-  if(ferror(DataFile)) {
-    fclose(DataFile);
-	DataFile = NULL;
-	State(FATAL, "Error writing to data file, closed file (%s)", strerror(errno));
-  }
-
-  // Update datafile size service (not every time to avoid infinite loop)
-  if (time(NULL) - DataSizeLastUpdate > SizeUpdateDelay) {
-    fflush(DataFile); // not continuously to reduce load
-
-	DataSizekB = FileSize(DataFile);
-	DataSizeService->updateService();
-	DataSizeLastUpdate = time(NULL);
-  }
-  
-  } // Check for MinAbsChange
-
-  //
-  // ====== Part D: Handle history service ===
-  //
-  
-  if (Info->getSize() == 0) return;
-  
-  // Check if data should be added to history buffer
-  char *Text = EvidenceServer::ToString(Info);
-  if (Text != NULL && strcmp(Info->getFormat(),"C") != 0
-	  && fabs(atof(Text)-List[Service].LastValue) < fabs(List[Service].MinAbsChange)) {
-	free(Text);
-	return;
-  }
-  free(Text);
-
+	// Minimum change?
+	if (fabs(Sum-List[Service].LastValue) < fabs(List[Service].MinAbsChange)) return;
+	List[Service].LastValue = Sum;
+  }
+  
   // Check if data fits into buffer
-  if (HistSize < Info->getSize() + 5*sizeof(int)) return;
+  if (List[Service].HistSize < Info->getSize() + 5*sizeof(int)) return;
 
   int Size = Info->getSize() + 4*sizeof(int), Next = List[Service].Next;
@@ -387,5 +378,5 @@
 
   // Check if buffer wrap-around (write wrap mark after Oldest is adjusted)
-  if (Next + Size >= HistSize) {
+  if (Next + Size >= List[Service].HistSize) {
     WrapPos = Buffer + Next;
     Next = 4;
@@ -482,18 +473,20 @@
   // Set minimum required change by comparing to regular expressions
   New.MinAbsChange = 0;
+  New.HistSize = MIN_HIST_SIZE;
   for (int i=0; i<RegExCount; i++) {
     if (regexec(&RegEx[i], Name.c_str(), (size_t) 0, NULL, 0) == 0) {
 	  New.MinAbsChange = MinChange[i];
+	  New.HistSize = HistSize[i];
 	}
   }
 
   // Create history service
-  New.Buffer = new char [HistSize];
-  memset(New.Buffer, 0, HistSize);
+  New.Buffer = new char [New.HistSize];
+  memset(New.Buffer, 0, New.HistSize);
   *(int *) New.Buffer = 4;
   New.Next = 4;
   New.LastValue = DBL_MAX;
   New.HistService = new DimService ((Name+".hist").c_str(), (char *) "C",
-  					  New.Buffer, HistSize);
+  					  New.Buffer, New.HistSize);
 
   // Load history buffer from file if existing
@@ -503,7 +496,7 @@
   if (File != NULL) {
     // Only load if current buffer size if equal or larger
-    if (FileSize(File) <= HistSize*sizeof(char)+sizeof(New.Next) && FileSize(File) != -1) {
+    if (FileSize(File) <= New.HistSize*sizeof(char)+sizeof(New.Next) && FileSize(File) != -1) {
       fread(&New.Next, sizeof(New.Next), 1, File);
-      fread(New.Buffer, sizeof(char), HistSize, File);
+      fread(New.Buffer, sizeof(char), New.HistSize, File);
       fclose(File);
 	}
@@ -516,4 +509,34 @@
   List.push_back(New);
 }
+
+
+//
+// Remove service from watch list
+//
+void DataHandler::RemoveService(string Name) {
+
+  // Find service index
+  vector<struct Item>::iterator E;
+  for (E=List.begin(); E<List.end(); ++E) if (Name == (*E).DataItem->getName()) {
+	// Delete subscription first so handler and not called anymore
+	delete (*E).DataItem;
+
+	// Save history buffer (replace '/' by '_')
+    string Name = (*E).HistService->getName();
+	for (int j=0; j<Name.size(); j++) if (Name[j] == '/') Name[j] = '_';
+    FILE *File = fopen((HistDir + "/" + Name).c_str(), "wb");
+	if (File != NULL) {
+      fwrite(&(*E).Next, sizeof((*E).Next), 1, File);
+      fwrite((*E).Buffer, sizeof(char), (*E).HistSize, File);
+      fclose(File);
+	}
+	
+	// Delete history service and free memory
+	delete (*E).HistService;
+    delete[] (*E).Buffer;
+	List.erase(E);
+  }
+}
+
 
 //
