public MessageHookEnvironment(MessageModel msg, string sender, string receiver) { if (msg == null) { throw new ArgumentNullException("msg"); } if (sender == null) { throw new ArgumentNullException("sender"); } if (receiver == null) { throw new ArgumentNullException("receiver"); } var nick = msg.GetNick(); var message = msg.ToString(); if (String.IsNullOrEmpty(nick)) { this["MSG"] = message; } else { this["MSG"] = message.Substring(nick.Length + 3); } this["MSG_TYPE"] = msg.MessageType.ToString(); var timestamp = (Int64) (msg .TimeStamp - UnixEpoch).TotalSeconds; this["MSG_TIMESTAMP_UNIX"] = timestamp.ToString(); this["MSG_TIMESTAMP_ISO_UTC"] = msg.TimeStamp.ToString("u").Replace('Z', ' ').TrimEnd(); this["MSG_TIMESTAMP_ISO_LOCAL"] = msg.TimeStamp.ToLocalTime().ToString("u").Replace('Z', ' ').TrimEnd(); this["SENDER"] = sender; this["RECEIVER"] = receiver; }
public override void Add(MessageModel msg) { if (msg == null) { throw new ArgumentNullException("msg"); } /* * if (MaxCapacity > 0 && Index.Count >= MaxCapacity) { * RemoveAt(0); * } */ var msgFileName = String.Format("{0}.v1.json", MessageNumber++); var msgFilePath = Path.Combine(RepositoryPath, msgFileName); using (var writer = File.OpenWrite(msgFilePath)) using (var textWriter = new StreamWriter(writer, Encoding.UTF8)) { JsonSerializer.SerializeToWriter(msg, textWriter); } DateTime start, stop; lock (Repository) { start = DateTime.UtcNow; var index = Repository.Index; //index.Stage(msgFilePath); // OPT: Stage() writes the index to disk on each call index.AddToIndex(msgFileName); stop = DateTime.UtcNow; } #if LOG4NET && MSGBUF_DEBUG f_Logger.DebugFormat("Add(): Index.AddToIndex() took: {0:0.00} ms", (stop - start).TotalMilliseconds); #endif // FIXME: delete file when index was written to disk File.Delete(msgFilePath); lock (CommitMessage) { CommitMessage.Append( String.Format("{0}: {1}\n", msgFileName, msg.ToString()) ); } // TODO: create tree, commit tree, repack repo reguraly (see rugged docs) }
public void Add(MessageModel msg) { if (msg == null) { throw new ArgumentNullException("msg"); } var cmd = Connection.CreateCommand(); cmd.CommandText = "INSERT INTO Messages (ID, Text)" + " VALUES(DEFAULT, @text)"; var param = cmd.CreateParameter(); param.ParameterName = "text"; param.Value = msg.ToString(); cmd.ExecuteNonQuery(); }
public MessageHookEnvironment(MessageModel msg, string sender, string receiver) { if (msg == null) { throw new ArgumentNullException("msg"); } if (sender == null) { throw new ArgumentNullException("sender"); } if (receiver == null) { throw new ArgumentNullException("receiver"); } var nick = msg.GetNick(); var message = msg.ToString(); if (String.IsNullOrEmpty(nick)) { this["MSG"] = message; } else { this["MSG"] = message.Substring(nick.Length + 3); } this["MSG_TYPE"] = msg.MessageType.ToString(); var timestamp = (Int64)(msg.TimeStamp - UnixEpoch).TotalSeconds; this["MSG_TIMESTAMP_UNIX"] = timestamp.ToString(); this["MSG_TIMESTAMP_ISO_UTC"] = msg.TimeStamp.ToString("u").Replace('Z', ' ').TrimEnd(); this["MSG_TIMESTAMP_ISO_LOCAL"] = msg.TimeStamp.ToLocalTime().ToString("u").Replace('Z', ' ').TrimEnd(); this["SENDER"] = sender; this["RECEIVER"] = receiver; }
int GetSenderPrefixWidth(MessageModel msg) { // HACK: try to obtain the nickname from the message // TODO: extend MessageModel with Origin property var msgText = msg.ToString(); var nickMatch = Regex.Match(msgText, "^(<([^ ]+)> )"); if (nickMatch.Success) { // HACK: the nick can be bold if (msg.MessageParts.Count >= 3) { // possibly colored nick, see MessageBuilder.CreateNick() var prefixPart = msg.MessageParts[0]; var nickPart = msg.MessageParts[1]; var suffixPart = msg.MessageParts[2]; if (prefixPart.ToString() == "<" && nickPart is TextMessagePartModel && suffixPart.ToString().StartsWith(">")) { // colored nick var nickTextPart = (TextMessagePartModel) nickPart; if (nickTextPart.Bold) { return GetPangoWidth( String.Format( "{0}<b>{1}</b>{2} ", GLib.Markup.EscapeText("<"), GLib.Markup.EscapeText( nickMatch.Groups[2].Value ), GLib.Markup.EscapeText(">") ), true ); } } } return GetPangoWidth(nickMatch.Groups[1].Value, false); } else { var eventMatch = Regex.Match(msgText, "^(-!- )"); if (eventMatch.Success && eventMatch.Groups.Count >= 2) { return GetPangoWidth(eventMatch.Groups[1].Value, false); } } return 0; }
void ShowNotification(ChatView chatView, MessageModel msg) { Notification notification; if (!Capabilites.Contains("append") && Notifications.TryGetValue(chatView, out notification)) { // no support for append, update the existing notification notification.Body = GLib.Markup.EscapeText( msg.ToString() ); return; } notification = new Notification() { Summary = chatView.Name, Category = "im.received" }; if (Capabilites.Contains("body")) { // notify-osd doesn't like unknown tags when appending notification.Body = GLib.Markup.EscapeText( msg.ToString() ); } //notification.IconName = "notification-message-im"; if (Capabilites.Contains("icon-static")) { if (chatView is PersonChatView) { notification.Icon = PersonChatIconPixbuf; } if (chatView is GroupChatView) { notification.Icon = GroupChatIconPixbuf; } } if (Capabilites.Contains("actions")) { notification.AddAction("show", _("Show"), delegate { try { MainWindow.PresentWithServerTime(); MainWindow.Notebook.CurrentChatView = chatView; notification.Close(); } catch (Exception ex) { #if LOG4NET Logger.Error("OnChatViewMessageHighlighted() " + "notification.Show threw exception", ex); #endif } }); } if (Capabilites.Contains("append")) { notification.AddHint("append", String.Empty); } if (Capabilites.Contains("sound")) { // DNS 0.9 only supports sound-file which is a file path // http://www.galago-project.org/specs/notification/0.9/x344.html // DNS 1.1 supports sound-name which is an id, see: // http://people.canonical.com/~agateau/notifications-1.1/spec/ar01s08.html // http://0pointer.de/public/sound-naming-spec.html // LAMESPEC: We can't tell which of those are actually // supported by this version as hint are totally optional :/ // HACK: always pass both hints when possible notification.AddHint("sound-name", "message-new-instant"); if (SoundFile != null) { notification.AddHint("sound-file", SoundFile); } } notification.Closed += delegate { try { #if LOG4NET Logger.Debug("OnChatViewMessageHighlighted(): received " + "notification.Closed signal for: " + chatView.Name); #endif Notifications.Remove(chatView); } catch (Exception ex) { #if LOG4NET Logger.Error("OnChatViewMessageHighlighted(): " + "Exception in notification.Closed handler", ex); #endif } }; notification.Show(); if (!Notifications.ContainsKey(chatView)) { Notifications.Add(chatView, notification); } }
string GetNick(MessageModel msg) { // HACK: try to obtain the nickname from the message // TODO: extend MessageModel with Origin property var msgText = msg.ToString(); var match = Regex.Match(msgText, "^<([^ ]+)>"); if (match.Success && match.Groups.Count >= 2) { return match.Groups[1].Value; } return null; }
void ShowNotification(ChatView chatView, MessageModel msg) { Notification notification; if (!Capabilites.Contains("append") && Notifications.TryGetValue(chatView, out notification)) { // no support for append, update the existing notification notification.Body = GLib.Markup.EscapeText( msg.ToString() ); return; } notification = new Notification() { Summary = chatView.Name, Category = "im.received" }; notification.AddHint("desktop-entry", "smuxi-frontend-gnome"); if (Capabilites.Contains("body")) { // notify-osd doesn't like unknown tags when appending notification.Body = GLib.Markup.EscapeText( msg.ToString() ); } if (Capabilites.Contains("icon-static")) { Gdk.Pixbuf iconData = null; string iconName = null; if (chatView is PersonChatView) { iconData = PersonChatIconPixbuf; iconName = "smuxi-person-chat"; } else if (chatView is GroupChatView) { iconData = GroupChatIconPixbuf; iconName = "smuxi-group-chat"; } var theme = Gtk.IconTheme.Default; #if DISABLED // OPT: use icon path/name if we can, so the image (26K) is not // send over D-Bus. Especially with the gnome-shell this is a // serious performance issue, see: // https://bugzilla.gnome.org/show_bug.cgi?id=683829 if (iconName != null && theme.HasIcon(iconName)) { // HACK: use icon path instead of name as gnome-shell does // not support icon names correctly, see: // https://bugzilla.gnome.org/show_bug.cgi?id=665957 var iconInfo = theme.LookupIcon(iconName, 256, Gtk.IconLookupFlags.UseBuiltin); if (!String.IsNullOrEmpty(iconInfo.Filename) && File.Exists(iconInfo.Filename) && ServerVendor == "GNOME" && (ServerName == "Notification Daemon" || ServerName == "gnome-shell")) { // HACK: notification-daemon 0.7.5 seems to ignore // the image_path hint for some reason, thus we have to // rely on app_icon instead, see: // https://bugzilla.gnome.org/show_bug.cgi?id=684653 // HACK: gnome-shell 3.4.2 shows no notification at all // with image_path and stops responding to further // notifications which freezes Smuxi completely! notification.IconName = "file://" + iconInfo.Filename; } else if (!String.IsNullOrEmpty(iconInfo.Filename) && File.Exists(iconInfo.Filename) && SpecificationVersion >= new Version("1.1")) { // starting with DNS >= 1.1 we can use the image-path // hint instead of icon_data or app_icon var hintName = "image_path"; if (SpecificationVersion >= new Version("1.2")) { hintName = "image-path"; } notification.AddHint(hintName, "file://" + iconInfo.Filename); } else { // fallback to icon_data as defined in DNS 0.9 notification.Icon = iconData; } #endif if (Frontend.HasSystemIconTheme && iconName != null && theme.HasIcon(iconName)) { notification.IconName = iconName; } else if (iconName != null && theme.HasIcon(iconName)) { // icon wasn't in the system icon theme var iconInfo = theme.LookupIcon(iconName, 256, Gtk.IconLookupFlags.UseBuiltin); if (!String.IsNullOrEmpty(iconInfo.Filename) && File.Exists(iconInfo.Filename)) { notification.IconName = "file://" + iconInfo.Filename; } } else if (iconData != null) { // fallback to icon_data as the icon is not available in // the theme notification.Icon = iconData; } else { // fallback for non-group/person messages notification.IconName = "notification-message-im"; } } else { // fallback to generic icon notification.IconName = "notification-message-im"; } if (Capabilites.Contains("actions")) { notification.AddAction("show", _("Show"), delegate { try { MainWindow.PresentWithServerTime(); ChatViewManager.CurrentChatView = chatView; notification.Close(); } catch (Exception ex) { #if LOG4NET Logger.Error("OnChatViewMessageHighlighted() " + "notification.Show threw exception", ex); #endif } }); } if (Capabilites.Contains("append")) { notification.AddHint("append", String.Empty); } if (Capabilites.Contains("sound")) { // DNS 0.9 only supports sound-file which is a file path // http://www.galago-project.org/specs/notification/0.9/x344.html // DNS 1.1 supports sound-name which is an id, see: // http://people.canonical.com/~agateau/notifications-1.1/spec/ar01s08.html // http://0pointer.de/public/sound-naming-spec.html // LAMESPEC: We can't tell which of those are actually // supported by this version as hint are totally optional :/ // HACK: always pass both hints when possible notification.AddHint("sound-name", "message-new-instant"); if (SoundFile != null) { notification.AddHint("sound-file", SoundFile); } } notification.Closed += delegate { try { #if LOG4NET Logger.Debug("OnChatViewMessageHighlighted(): received " + "notification.Closed signal for: " + chatView.Name); #endif Notifications.Remove(chatView); } catch (Exception ex) { #if LOG4NET Logger.Error("OnChatViewMessageHighlighted(): " + "Exception in notification.Closed handler", ex); #endif } }; notification.Show(); if (!Notifications.ContainsKey(chatView)) { Notifications.Add(chatView, notification); } } void OnMainWindowFocusInEvent(object sender, Gtk.FocusInEventArgs e) { Trace.Call(sender, e); if (MainWindow.Notebook.IsBrowseModeEnabled) { return; } var currentChatView = ChatViewManager.CurrentChatView; if (currentChatView == null) { return; } DisposeNotification(currentChatView); } void OnMainWindowNotebookSwitchPage(object sender, Gtk.SwitchPageArgs e) { Trace.Call(sender, e); if (MainWindow.Notebook.IsBrowseModeEnabled) { return; } var currentChatView = ChatViewManager.CurrentChatView; if (currentChatView == null) { return; } DisposeNotification(currentChatView); } void DisposeNotification(ChatView chatView) { Notification notification; if (!Notifications.TryGetValue(chatView, out notification)) { return; } #if LOG4NET Logger.Debug("DisposeNotification(): disposing notification for: " + chatView.Name); #endif try { // don't try to close already closed notifications (timeout) if (notification.Id == 0) { #if LOG4NET Logger.Debug("DisposeNotification(): notification already " + "closed for: " + chatView.Name); #endif return; } notification.Close(); } catch (Exception ex) { #if LOG4NET Logger.Error("DisposeNotification(): " + "notification.Close() thew exception", ex); #endif } finally { Notifications.Remove(chatView); } }
public override void Add(MessageModel msg) { if (msg == null) { throw new ArgumentNullException("msg"); } /* if (MaxCapacity > 0 && Index.Count >= MaxCapacity) { RemoveAt(0); } */ var msgFileName = String.Format("{0}.v1.json", MessageNumber++); var msgFilePath = Path.Combine(RepositoryPath, msgFileName); using (var writer = File.OpenWrite(msgFilePath)) using (var textWriter = new StreamWriter(writer, Encoding.UTF8)) { JsonSerializer.SerializeToWriter(msg, textWriter); } DateTime start, stop; lock (Repository) { start = DateTime.UtcNow; var index = Repository.Index; //index.Stage(msgFilePath); // OPT: Stage() writes the index to disk on each call index.AddToIndex(msgFileName); stop = DateTime.UtcNow; } #if LOG4NET && MSGBUF_DEBUG f_Logger.DebugFormat("Add(): Index.AddToIndex() took: {0:0.00} ms", (stop - start).TotalMilliseconds); #endif // FIXME: delete file when index was written to disk File.Delete(msgFilePath); lock (CommitMessage) { CommitMessage.Append( String.Format("{0}: {1}\n", msgFileName, msg.ToString()) ); } // TODO: create tree, commit tree, repack repo reguraly (see rugged docs) }
public void UpdateTopicInGroupChat(GroupChatModel cpage, MessageModel topic) { Trace.Call(cpage, topic); Console.WriteLine("Topic changed to: " + topic.ToString() + " on " + cpage.Name); }
public void LogMessage(ChatModel chat, MessageModel msg, bool isFiltered) { if (chat == null) { throw new ArgumentNullException("chat"); } if (msg == null) { throw new ArgumentNullException("msg"); } if (!(bool) UserConfig["Logging/Enabled"]) { return; } if (isFiltered && !(bool) UserConfig["Logging/LogFilteredMessages"]) { return; } if (chat.ChatType == ChatType.Session || chat.ChatType == ChatType.Protocol) { return; } try { // HACK: twitter retrieves older messages and we don't want to // re-log those when the twitter connection is re-opened var protocol = chat.ProtocolManager.Protocol.ToLower(); if (protocol == "twitter") { return; } using (var stream = File.AppendText(chat.LogFile)) { stream.WriteLine( String.Format( "[{0:yyyy-MM-dd HH:mm:ss}] {1}", msg.TimeStamp.ToLocalTime(), msg.ToString() ) ); } } catch (Exception ex) { #if LOG4NET f_Logger.Error("LogMessage(): logging error", ex); #endif } }
public bool IsFilteredMessage(ChatModel chat, MessageModel msg) { if (chat == null) { throw new ArgumentNullException("chat"); } if (msg == null) { throw new ArgumentNullException("msg"); } return IsFilteredMessage(chat, msg.ToString(), msg.MessageType); }
public void UpdateTopicInGroupChat(GroupChatModel groupChat, MessageModel topic) { if (groupChat == null) { throw new ArgumentNullException("groupChat"); } if (topic == null) { throw new ArgumentNullException("topic"); } #if LOG4NET f_Logger.Debug("UpdateTopicInGroupChat() groupChat.Name: " + groupChat.Name + " topic: " + topic.ToString()); #endif groupChat.Topic = topic; lock (_FrontendManagers) { foreach (FrontendManager fm in _FrontendManagers.Values) { fm.UpdateTopicInGroupChat(groupChat, topic); } } }