Index: Evidence/Edd/Edd.cc
===================================================================
--- Evidence/Edd/Edd.cc	(revision 221)
+++ Evidence/Edd/Edd.cc	(revision 222)
@@ -27,16 +27,18 @@
 QWidget *OpenHistory(char *Service, int Index) {
 
-  char *Name, *Format;
-  DimBrowser Browser;
-
-  // If status service displayed as text history
-  if (strstr(Service, "/Message") != NULL) return new EddText(Service);
-
-  // If service currently not available, default open as plot
-  Browser.getServices(Service);
-  if (Browser.getNextService(Name, Format) != DimSERVICE) return new EddPlot(Service, Index);
-  
-  // Otherwise, determine from format if plot or text history
-  if (strlen(Format) == 1 && *Format != 'C') return new EddPlot(Service, Index);
+  class EvidenceHistory *Hist = Handler->GetHistory(Service);
+
+  // Check if hitory service available
+  if (Hist == NULL || Hist->GetFormat() == NULL) {
+	QMessageBox::warning(NULL, "Edd Message", QString("Could not retrieve history for service ") + Service ,QMessageBox::Ok);
+	Handler->DropHistory(Service);
+	return NULL;
+  }
+
+  QString Format = Hist->GetFormat();
+  Handler->DropHistory(Service);
+  
+  //if (strlen(Hist->GetFormat()) == 1 && *Hist->GetFormat() != 'C') return new EddPlot(Service, Index);
+  if (Format.size() == 1 && Format[0] != 'C') return new EddPlot(Service, Index);
   else return new EddText(Service);
 }
@@ -66,5 +68,5 @@
 	QLineEdit(P), ServiceName(Name), Index(Index) {
 
- LastPlot = NULL;
+ LastHist = NULL;
  
   // Widget properties
@@ -135,5 +137,5 @@
   // Check if last history plot still open, then raise
   foreach (QWidget *Widget, QApplication::allWidgets()) {
-    if (Widget == LastPlot) {
+    if (Widget == LastHist) {
       Widget->activateWindow();
       Widget->raise();
@@ -177,6 +179,6 @@
 void EddLineDisplay::MenuOpenHistory() {
   
-  LastPlot = OpenHistory(ServiceName.toAscii().data(), Index);
-  if (LastPlot != NULL) LastPlot->show();
+  LastHist = OpenHistory(ServiceName.toAscii().data(), Index);
+  if (LastHist != NULL) LastHist->show();
 }
 
@@ -295,5 +297,5 @@
 		double Number=0;
 		while ((R=Hist->Next()) != NULL) {
-		  switch (Format[0].toUpper().toAscii()) {
+		  switch (*(Hist->GetFormat())) {
     		case 'I':
 			case 'L':  Number = *((int *) R->Data + List[ItemNo].Index);   break;
@@ -311,4 +313,5 @@
 		if (SizeLimit < 2*Count) SizeLimit = 2*Count;
 	  }
+	  Handler->DropHistory(List[ItemNo].Name);
 	}
 
@@ -737,4 +740,5 @@
 	  }
 	}
+	Handler->DropHistory(Name);
   }
 
@@ -876,6 +880,22 @@
 }
 
-// Update throughput statistics
+// Reduce history usage counter
+void EddDim::DropHistory(QString Name) {
+
+  for (int i=0; i<HistoryList.size(); i++) {
+	if (HistoryList[i].Name == Name) HistoryList[i].Count--;
+  }
+}
+
+// Update throughput statistics and clear up history memory
 void EddDim::UpdateStatistics() {
+
+  // Remove unused histories after not less than 5 seconds
+  for (int i=0; i<HistoryList.size(); i++) {
+	if ((HistoryList[i].Count <= 0) && (time(NULL)-HistoryList[i].LastUpdate) > 5) { 
+	  delete HistoryList[i].HistClass;
+	  HistoryList.removeAt(i);
+	}
+  }
 
   // Lock before accessing internal variables
@@ -1534,5 +1554,5 @@
   getServices("*");
   while ((Type = getNextService(Name, Format)) != 0) {
-    if (Type==DimSERVICE && strstr(Name, ".hist")==NULL) List.append(Name);
+    if (Type==DimSERVICE) List.append(Name);
   }
   List.sort();
@@ -1543,5 +1563,4 @@
   if (OK && !Result.isEmpty()) {
     Result = Result.trimmed();
-    if (Result.endsWith(".hist")) Result.chop(5);
     QWidget *Hist = OpenHistory(Result.toAscii().data(), 0);
     if (Hist != NULL) Hist->show();
Index: Evidence/Edd/Edd.h
===================================================================
--- Evidence/Edd/Edd.h	(revision 221)
+++ Evidence/Edd/Edd.h	(revision 222)
@@ -96,5 +96,5 @@
     QMenu *Menu;
     QPoint dragStart;
-    QWidget *LastPlot;
+    QWidget *LastHist;
 	
 	QString ServiceName;
@@ -247,4 +247,5 @@
 	void Unsubscribe (QString);
 	class EvidenceHistory *GetHistory(QString);
+	void DropHistory(QString);
 
   signals:
Index: Evidence/Evidence.cc
===================================================================
--- Evidence/Evidence.cc	(revision 221)
+++ Evidence/Evidence.cc	(revision 222)
@@ -388,4 +388,5 @@
 
   memcpy(Buffer, R.getData(), BufferSize);
+  DataStart = Buffer + strlen(Buffer) + 1;
   Rewind();
   
@@ -399,11 +400,10 @@
 
   // Check for wrap around
-  if (memcmp(Pointer, &WrapMark, sizeof(WrapMark)) == 0) Pointer = (struct Item *) (Buffer + 4);
-  
+  if (memcmp(Pointer, &WrapMark, sizeof(WrapMark)) == 0) Pointer = (struct Item *) (DataStart + sizeof(int));
   // Check if at end of ring buffer
   if (memcmp(Pointer, &EndMark, sizeof(EndMark)) == 0) return NULL;
 
   const struct Item *Ret = Pointer;
-  Pointer = (struct Item *) ((char *) (Pointer + 1) + Pointer->Size);
+  Pointer = (struct Item *) ((char *) (Ret + 1) + Ret->Size);
 
   return Ret;
@@ -413,4 +413,10 @@
 void EvidenceHistory::Rewind() {
 
-  if (Buffer != NULL) Pointer = (struct Item *) (Buffer + (*(int *) Buffer));
-}
+  if (Buffer != NULL) Pointer = (struct Item *) (DataStart + (*(int *) DataStart));
+}
+
+// Return DIM format string of service (NULL if no data)
+char *EvidenceHistory::GetFormat() {
+
+  return Buffer;
+}
Index: Evidence/Evidence.h
===================================================================
--- Evidence/Evidence.h	(revision 221)
+++ Evidence/Evidence.h	(revision 222)
@@ -81,5 +81,5 @@
 	  int Time;
 	  int Size;
-	  char Data[]; // Size bytes
+	  char Data[]; // Size bytes follow
 	} __attribute__((packed));
 
@@ -91,4 +91,5 @@
 	char *Buffer;
 	int BufferSize;
+	char *DataStart;
 	struct Item *Pointer;
 	
@@ -98,4 +99,5 @@
 
 	bool GetHistory();
+	char *GetFormat();
 	const struct Item *Next();
 	void Rewind();
Index: Evidence/History.cc
===================================================================
--- Evidence/History.cc	(revision 221)
+++ Evidence/History.cc	(revision 222)
@@ -23,5 +23,4 @@
 
 #include <string>
-#include <sstream>
 #include <vector>
 #include <math.h>
@@ -42,4 +41,5 @@
 	  double LastValue;
 	  double MinAbsChange;
+	  string Format;
 	};
 	vector<struct Item> List;
@@ -51,5 +51,5 @@
     void infoHandler();
     void rpcHandler();
-	void AddService(string);
+	void AddService(string, const char *);
 	void RemoveService(string);
 	off_t FileSize(FILE *);
@@ -97,5 +97,5 @@
 	char *Token = strtok(I->getString(), "+-!@");	
 	while (Token != NULL) {
-	  AddService(string(Token)+"/SERVICE_LIST"); // 'add' also for '-' and '!'
+	  AddService(string(Token)+"/SERVICE_LIST", "C"); // 'add' also for '-' and '!'
 	  Token = strtok(NULL, "|"); // Skip server IP address
 	  Token = strtok(NULL, "@");
@@ -104,13 +104,17 @@
   }
 
-  // If service is SERVICE_LIST of any server, scan all services.
-  // Subscribe to all services (but not to commands and RPCs)
+  // If service is SERVICE_LIST, scan and subscribe/unsubscribe to services
   if (strstr(I->getName(), "/SERVICE_LIST") != NULL) {
-	char *Name = strtok(I->getString(), "+-!|");
+	char *Type, *Name = strtok(I->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 (strstr(Type, "|CMD")==NULL && strstr(Type, "|RPC")==NULL) AddService(Name); // 'add' also for '-' and '!'
+	  // Only consider DIM services (not commands and RPCs)
+      if (((Type = strtok(NULL, "\n")) != NULL) &&
+		  (strstr(Type, "|CMD") == NULL) && (strstr(Type, "|RPC") == NULL)) {
+	    if (*I->getString() == '-' || *I->getString() == '!') RemoveService(Name);
+		else {
+		  Type[strlen(Type)-1] = '\0'; // Isolate service format
+		  AddService(Name, Type);
+		}
+	  }
 	  Name = strtok(NULL, "|");
 	}
@@ -161,5 +165,5 @@
   if (Next + Size >= List[Service].Buffer.size()) {
     WrapPos = Buffer + Next;
-    Next = 4;
+    Next = sizeof(int);
   }
 
@@ -169,5 +173,5 @@
 	// Check for wrap-around
 	if (memcmp(Buffer + Oldest, &EvidenceHistory::WrapMark, sizeof(EvidenceHistory::WrapMark)) == 0) {
-	  Oldest = 4;
+	  Oldest = sizeof(int);
 	  continue;
 	}
@@ -205,5 +209,10 @@
   for (int i=0; i<List.size(); i++) {
     if (strcmp(List[i].DataItem->getName(), getString()) == 0) {
-	  setData((void *) &List[i].Buffer[0], List[i].Buffer.size());
+	  char *Buffer = new char [List[i].Format.size()+1+List[i].Buffer.size()];
+	  strcpy(Buffer, List[i].Format.c_str());
+	  memcpy(Buffer+List[i].Format.size()+1, &List[i].Buffer[0], List[i].Buffer.size());
+//	  setData((void *) &List[i].Buffer[0], List[i].Buffer.size());
+	  setData((void *) Buffer, List[i].Format.size()+1+List[i].Buffer.size());
+	  delete[] Buffer;
 	  return;
 	}
@@ -217,11 +226,10 @@
   }
 
-  // Read history file
+  // Read history file and send to client (data will contain format string and history)
   off_t Size = FileSize(File);
   if (Size != -1) {
 	char *Buffer = new char [Size-sizeof(int)];
-	fseek(File, sizeof(int), SEEK_SET);
-	fread(Buffer, sizeof(char), Size-sizeof(int), File);
-	if (ferror(File) != 0) {
+	fseek(File, sizeof(int), SEEK_SET); // Skip 'Next' pointer
+	if ((fread(Buffer, sizeof(char), Size-sizeof(int), File) != Size-sizeof(int)) || (ferror(File) != 0)) {
 	  Message(WARN, "Error reading history file '%s' in rpcHandler()", getString());
 	  setData(NULL, 0);		// Default response
@@ -238,5 +246,5 @@
 // Add service to watch list
 //
-void History::AddService(string Name) {
+void History::AddService(string Name, const char *Format) {
 
   // Check if already subscribed to this service
@@ -247,4 +255,5 @@
   struct Item New;
   New.LastValue = DBL_MAX;
+  New.Format = Format;
 
   // Set minimum required change if given in configuratrion
@@ -258,7 +267,15 @@
 
   if (File != NULL && (Size = FileSize(File)) != -1) {
+
+    // If current buffer too small, resize
 	if (Size > New.Buffer.size()) New.Buffer.resize(Size);
+
+	// Read next pointer
     fread(&New.Next, sizeof(New.Next), 1, File);
+	// Skip format string
+	while (fgetc(File) != 0 && feof(File) == 0) {}
+	// Read buffer
     fread(&New.Buffer[0], sizeof(char), Size, File);
+
 	if (ferror(File) != 0) {
 	  Message(WARN, "Error reading history file '%s' in AddService()", Name.c_str());
@@ -297,12 +314,16 @@
 	FILE *File = OpenFile(Name, "wb");
 	if (File != NULL) {
-      fwrite(&(*E).Next, sizeof((*E).Next), 1, File);
-      fwrite(&(*E).Buffer[0], sizeof(char), (*E).Buffer.size(), File);
-	  if (ferror(File) != 0) Message(WARN, "Error writing history file '%s' in RemoveService()", Name.c_str());
+      fwrite(&(*E).Next, sizeof((*E).Next), 1, File);					// Next pointer
+      fwrite((*E).Format.c_str(), (*E).Format.size()+1, 1, File);		// Format
+      fwrite(&(*E).Buffer[0], sizeof(char), (*E).Buffer.size(), File);	// Buffer
+
+	  // If error, try to delete (possibly erroneous) file 
+	  if (ferror(File) != 0) {
+		if (remove(Name.c_str()) == -1) Message(WARN, "Error writing history file '%s' in RemoveService(), could also not delete file", Name.c_str());
+		else Message(WARN, "Error writing history file '%s' in RemoveService(), deleted file", Name.c_str());
+	  }
       if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in RemoveService()", Name.c_str());;
 	}
 	
-	// Delete history service and free memory
-    //delete[] (*E).Buffer;
 	List.erase(E);
   }
@@ -332,7 +353,11 @@
   if(mkdir(Directory, S_IRWXU|S_IRWXG)==-1 && errno!=EEXIST) return NULL;
 
-  // Replace all '/' by '_' in string and open file
-  for (int i=0; i<Service.size(); i++) if (Service[i] == '/') Service[i] = '_';
-  return fopen((Directory + Service).c_str(), Mode);
+  // Replace all '/' and non-graphical characters by '_' in string and open file
+  for (int i=0; i<Service.size(); i++) {
+	if (Service[i] == '/') Service[i] = '_';
+	if (isgraph(Service[i]) == 0) Service[i] = '_';
+  }
+
+  return fopen((string(Directory) + "/" + Service).c_str(), Mode);
 }
 
Index: Evidence/readme.txt
===================================================================
--- Evidence/readme.txt	(revision 221)
+++ Evidence/readme.txt	(revision 222)
@@ -36,5 +36,6 @@
 			Service quality now also written to slow data file.
 31/5/2010	Configuration file format now follows semi-standard INI format.
-7/6/2010	Separated History service from DColl.
+7/6/2010	Separated History service from DColl. History format changed, now includes
+			service format (allows history access also when service is unavailable).
 
 
