Logo Search packages:      
Sourcecode: galaxium version File versions  Download package

ConversationLogUtility.cs

/*
 * Galaxium Messenger
 * Copyright (C) 2007 Ben Motmans <ben.motmans@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#define USE_SQLITE

using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Collections.Generic;

using Galaxium.Core;
using Anculus.Core;

namespace Galaxium.Protocol
{
      //TODO: only create 1 instance for each log (re-use the same instance)
      public static class ConversationLogUtility
      {
            public static event EventHandler MaximumLogSizeChanged;
            
            public static event EventHandler LoggingEnabledChanged;
            
            private static bool _enableLogging;
            private static bool _enableEventLogging;
            
            private static string _logDirectory;
            
            private static int _maxLogSize;
            private static int _logChunkCount;
            
            private static IConfigurationSection _config;

            static ConversationLogUtility ()
            {
                  _logDirectory = Path.Combine (Path.GetFullPath (CoreUtility.ConfigurationDirectory), "History");
                  
                  _config = Configuration.Logging.Section;
                  
                  _enableLogging = _config.GetBool (Configuration.Logging.EnableLogging.Name, Configuration.Logging.EnableLogging.Default);
                  _enableEventLogging = _config.GetBool (Configuration.Logging.EnableEventLogging.Name, Configuration.Logging.EnableEventLogging.Default);
                  
                  int maxLogSize = _config.GetInt (Configuration.Logging.MaximumLogSize.Name, Configuration.Logging.MaximumLogSize.Default);
                  
                  if (maxLogSize < 262144)
                        maxLogSize = 262144;
                  
                  MaximumLogSize = maxLogSize;
            }
            
            public static int MaximumLogSize
            {
                  get {  return _maxLogSize; }
                  set {
                        //256kB = min, 2GB = max
                        
                        if (value == _maxLogSize)
                              return;
                        
                        if (value < 262144) //256kB
                              throw new ArgumentException ("MaximumLogSize must be >= 262144 (256kB)");

                        _maxLogSize = value;
                        _logChunkCount = GetLogChunkCount (_maxLogSize);
                        
                        _config.SetInt (Configuration.Logging.MaximumLogSize.Name, value);
                        
                        if (MaximumLogSizeChanged != null)
                              MaximumLogSizeChanged (null, EventArgs.Empty);
                  }
            }
            
            internal static int GetLogChunkCount (int bytes)
            {
                  if (bytes < (1024 * 1024 * 4))
                        return 4;
                  else if (bytes < (1024 * 1024 * 64))
                        return 8;
                  else if (bytes < (1024 * 1024 * 128))
                        return 16;
                  else if (bytes < (1024 * 1024 * 512))
                        return 32;
                  else
                        return 64;
            }
            
            public static bool EnableLogging
            {
                  get { return _enableLogging; }
                  set {
                        if (_enableLogging != value) {
                              _enableLogging = value;
                              
                              _config.SetBool (Configuration.Logging.EnableLogging.Name, value);
                              
                              if (LoggingEnabledChanged != null)
                                    LoggingEnabledChanged (null, EventArgs.Empty);
                        }
                  }
            }
            
            public static bool EnableEventLogging
            {
                  get { return _enableEventLogging; }
                  set {
                        if (_enableEventLogging != value) {
                              _enableEventLogging = value;
                              _config.SetBool (Configuration.Logging.EnableEventLogging.Name, value);
                        }
                  }
            }
            
            public static int LogChunkCount
            {
                  get { return _logChunkCount; }
            }
            
            public static int LogChunkSize
            {
                  get { return _maxLogSize / _logChunkCount; }
            }

            public static string LogDirectory
            {
                  get { return _logDirectory; }
            }
            
            public static bool ReadArchiveInfo (string directory, string logName, out int size, out int chunkCount)
            {
                  string filename = Path.Combine (directory, "archives.xml");
                  if (!File.Exists (filename)) {
                        size = _maxLogSize;
                        chunkCount = LogChunkCount;
                        return false;
                  }

                  using (Stream stream = File.OpenRead (filename)) {
                        using (XmlReader reader = new XmlTextReader (stream)) {
                              while (reader.Read ()) {
                                    if (reader.Depth != 1 || reader.LocalName != "archive" || reader.NodeType != XmlNodeType.Element)
                                          continue;
                                    
                                    string name = reader.GetAttribute ("name");
                                    if (name != logName)
                                          continue;
                                    
                                    string sizeString = reader.GetAttribute ("size");
                                    string chunkCountString = reader.GetAttribute ("chunkCount");
                                    
                                    if (!int.TryParse (sizeString, out size) || !int.TryParse (chunkCountString, out chunkCount))
                                          return false;
                                    
                                    return true;
                              }
                        }
                  }
                  
                  size = _maxLogSize;
                  chunkCount = LogChunkCount;
                  return false;
            }
            
            public static void WriteArchiveInfo (string directory, string logName, int size, int chunkCount)
            {
                  string filename = Path.Combine (directory, "archives.xml");
                  
                  XmlDocument doc = new XmlDocument ();
                  XmlElement rootElement = null;
                  
                  if (File.Exists (filename)) {
                        try {
                              doc.Load (filename);
                              rootElement = doc.DocumentElement;
                        } catch {}
                  } else {
                        rootElement = doc.CreateElement ("archives");
                        doc.AppendChild (rootElement);
                  }
                  
                  XmlElement archiveElement = null;
                  foreach (XmlNode node in rootElement.SelectNodes ("/archive")) {
                        if (node.NodeType != XmlNodeType.Element)
                              continue;
                        
                        XmlElement element = node as XmlElement;
                        
                        string name = element.GetAttribute ("name");
                        if (name != logName)
                              continue;
                        
                        archiveElement = element;
                        break;
                  }
                  
                  if (archiveElement == null) {
                        archiveElement = doc.CreateElement ("archive");
                        archiveElement.SetAttribute ("name", logName);
                        
                        rootElement.AppendChild (archiveElement);
                  }

                  archiveElement.SetAttribute ("size", size.ToString ());
                  archiveElement.SetAttribute ("chunkCount", chunkCount.ToString ());

                  doc.Save (filename);
            }

            public static IConversationLog GetConversationLog (IConversation conversation)
            {
                  ThrowUtility.ThrowIfNull ("conversation", conversation);
                  
                  string dir = GetLogDirectory (conversation.Session);
                  
                  string filename = null;
                  if (conversation.IsPrivateConversation || conversation.IsChannelConversation)
                  {
#if USE_SQLITE
                        return new SQLiteConversationLog (dir, conversation.PrimaryContact.UniqueIdentifier, true);
#else
                        return new IndexedConversationLog (dir, conversation.PrimaryContact.UniqueIdentifier, true);
#endif
                  }
                  else
                        return GetGroupConversationLog (dir, conversation);
            }
            
            public static IConversationLog GetConversationLog (IContact contact)
            {
                  ThrowUtility.ThrowIfNull ("contact", contact);

                  string dir = GetLogDirectory (contact.Session);
                  
#if USE_SQLITE
                  return new SQLiteConversationLog (dir, contact.UniqueIdentifier, true);
#else
                  return new IndexedConversationLog (dir, contact.UniqueIdentifier, true);
#endif
            }
            
            private static string GetLogDirectory (ISession session)
            {
                  IAccount account = session.Account;
                  
                  IProtocolFactory fac = ProtocolUtility.GetProtocolFactory (account.Protocol);
                  
                  if (fac == null)
                        return null;
                  
                  string dir = Path.Combine (Path.Combine (_logDirectory, fac.Protocol.Name), account.UniqueIdentifier);

                  if (!Directory.Exists (dir))
                        Directory.CreateDirectory (dir);
                  
                  return dir;
            }

            private static IConversationLog GetGroupConversationLog (string directory, IConversation conversation)
            {
                  string subdir = Path.Combine (directory, "GroupChats");
                  string lookupFile = Path.Combine (directory, "GroupChats.xml");
                  
                  if (!Directory.Exists (subdir))
                        Directory.CreateDirectory (subdir);
                  
                  Stream stream = File.Open (lookupFile, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                  using (stream) {
                        XmlReaderSettings settings = new XmlReaderSettings ();
                        settings.ConformanceLevel = ConformanceLevel.Fragment;
                        using (XmlReader reader = XmlReader.Create (stream, settings)) {
                              while (reader.Read ()) {
                                    if (reader.Depth > 1 || reader.LocalName != "ConversationLog" || reader.NodeType != XmlNodeType.Element)
                                          continue;
                                    
                                    string countString = reader.GetAttribute ("count");
                                    int count = 0;
                                    if (int.TryParse (countString, out count))
                                          if (count != conversation.ContactCollection.Count)
                                                continue;
                                    
                                    if (IsConversationMatch (conversation, reader.ReadSubtree ()))
                                    {
                                          string logName = reader.GetAttribute ("logName");
                                          
#if USE_SQLITE
                                          return new SQLiteConversationLog (subdir, logName, true);
#else
                                          return new IndexedConversationLog (subdir, logName, true);
#endif
                                    }
                              }
                        }

                        stream.Seek (stream.Length, SeekOrigin.Begin);
                        
                        using (XmlTextWriter writer = new XmlTextWriter (stream, Encoding.UTF8)) {
                              writer.WriteStartElement ("ConversationLog");
                              writer.WriteAttributeString ("logName", conversation.UniqueIdentifier.ToString ());
                              writer.WriteAttributeString ("count", conversation.ContactCollection.Count.ToString ());
                              
                              foreach (IContact contact in conversation.ContactCollection) {
                                    writer.WriteStartElement ("Contact");
                                    writer.WriteAttributeString ("uid", contact.UniqueIdentifier);
                                    writer.WriteEndElement ();
                              }
                              
                              writer.WriteEndElement ();
                              writer.Flush ();
                        }
                        
#if USE_SQLITE
                        return new SQLiteConversationLog (subdir, conversation.UniqueIdentifier.ToString (), true);
#else
                        return new IndexedConversationLog (subdir, conversation.UniqueIdentifier.ToString (), true);
#endif
                  }
            }
            
            private static bool IsConversationMatch (IConversation conversation, XmlReader reader)
            {
                  bool match = true;

                  while (reader.Read ()) {
                        if (reader.Depth != 2 || reader.LocalName != "Contact" || reader.NodeType != XmlNodeType.Element)
                              continue;
                                    
                        string uid = reader.GetAttribute ("uid");
                        
                        bool found = false;
                        foreach (IContact contact in conversation.ContactCollection) {
                              if (contact.UniqueIdentifier == uid) {
                                    found = true;
                                    break;
                              }
                        }
                        
                        if (!found) {
                              match = false;
                              break;
                        }
                        
                  }

                  reader.Close ();
                  return match;
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index