/** * Imports a single Trillian log. */ private void ImportLog(string protocol, TrillianLog log, IResource selfAccount) { // For ICQ, the first session does not contain the nickname of the correspondent. // Thus, to avoid creating number-only contacts, we buffer messages until we // get a real nick, then create the contact and account, process the messages from // the buffer and continue parsing normally. ArrayList messageBuffer = new ArrayList(); IResource correspondentAcct = FindTrillianAccount(protocol, log.GetName()); if (correspondentAcct != null) { // GetIntProp() returns 0 if the property was not defined int lastImportOffset = correspondentAcct.GetIntProp(_propLastImportOffset); // If the log size is less than the last import offset, it means that the // log was truncated. Redo import from start. if (lastImportOffset > log.Size) { lastImportOffset = 0; } if (lastImportOffset == log.Size) { // the log is already completely imported return; } log.Seek(lastImportOffset); } while (true) { TrillianLogMessage msg = log.ReadNextMessage(); if (msg == null) { break; } if (correspondentAcct == null) { int foo; if (protocol == "ICQ" && Int32.TryParse(log.CurCorrespondentName, out foo)) { messageBuffer.Add(msg); continue; } correspondentAcct = FindOrCreateTrillianAccount(protocol, log.GetName(), log.CurCorrespondentName); ImportFromBuffer(messageBuffer, selfAccount, correspondentAcct); messageBuffer.Clear(); } IResource fromAccount = msg.Incoming ? correspondentAcct : selfAccount; IResource toAccount = msg.Incoming ? selfAccount : correspondentAcct; IResource conversation = _convManager.Update(msg.Text, msg.Time, fromAccount, toAccount); // Request text indexing of the conversation. Repeated indexing requests // will be merged, so there is no harm in requesting to index the same // conversation multiple times. if (conversation != null) { _environment.TextIndexManager.QueryIndexing(conversation.Id); } } if (correspondentAcct == null && messageBuffer.Count > 0) { // no nickname until end of log => process messages accumulated in the buffer correspondentAcct = FindOrCreateTrillianAccount(protocol, log.GetName(), null); ImportFromBuffer(messageBuffer, selfAccount, correspondentAcct); } correspondentAcct.SetProp(_propLastImportOffset, log.Size); }
/** * Reads and returns the next message from the Trillian log. Returns * null if reached end of file. */ public TrillianLogMessage ReadNextMessage() { CheckCreateReader(); if (_eof) { return(null); } TrillianLogMessage curMessage = null; while (true) { DateTime offlineMessageDate = DateTime.MinValue; string line = ReadNextLine(); if (line == null) { _eof = true; break; } Match m = _sessionStartRx.Match(line); if (m.Success) { _curCorrespondent = m.Groups [1].Value; try { _curDate = DateTime.ParseExact(m.Groups [2].Value, "ddd MMM dd HH:mm:ss yyyy", CultureInfo.InvariantCulture); } catch (Exception) { Trace.WriteLine("Failed to parse Trillian date: " + m.Groups [2].Value); } continue; } if (line.StartsWith("Session Close (") || _serviceMessageRx.IsMatch(line)) { // Marks the end of a session or a service message (contact logon/logoff). // If we have a message, return it; otherwise, continue parsing if (curMessage != null) { break; } continue; } m = _offlineMessageRx.Match(line); if (m.Success) { // FIXME: extract date from offline message offlineMessageDate = ParseDate(_curDate, m.Groups [1].Value, m.Groups [2].Value); line = line.Substring(0, m.Index - 1); } line = _linkRx.Replace(line, "$1"); m = _messageStartRx.Match(line); if (m.Success) { // The line is the beginning of a new message following the current one. // Save it to the buffer and return the message. if (curMessage != null) { _nextLine = line; break; } string text = m.Groups [4].Value; DateTime dt = ParseDate(_curDate, m.Groups [1].Value, m.Groups [2].Value); string nick = m.Groups [3].Value; curMessage = new TrillianLogMessage(dt, (nick == _curCorrespondent), text); _curDate = dt; } else { // the line is a continuation of the current message if (curMessage != null) { curMessage.AddLine(line); } } if (curMessage != null && offlineMessageDate != DateTime.MinValue) { curMessage.Time = offlineMessageDate; } } return(curMessage); }