miranda/Speak/Speak/Fork/ContactManager.cs
2013-05-08 21:39:27 +00:00

637 lines
23 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using Virtuoso.Miranda.Plugins.Helpers;
using Virtuoso.Miranda.Plugins.Infrastructure;
using Virtuoso.Miranda.Plugins.Native;
using Speak.Core;
using Speak.HPP;
using Speak.RichEdit;
using Speak.Sites;
using Speak.Structs;
using Speak.UI;
using Speak.Utils;
namespace Speak.Fork
{
class ContactManager : IDisposable
{
internal class SettingOwner : ISettingOwner
{
private string name;
public SettingOwner(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
set { name = value; }
}
}
private string ownerProtocol;
//private ContactContainer juickContact;
private List<ContactContainer> siteContacts;
// todo: FIX IT!!!111
private const string namePrefix = "[xJuick] ";
private const string xJuickSiteField = "Site";
private List<ContactContainer> forkContacts;
private SettingOwner pOwner;
private SettingOwner mpOwner;
private SettingOwner clOwner;
private SettingOwner sOwner;
private IntPtr rootName;
private bool addAsTemporary;
private StatusModes mode;
private Dictionary<string, ISite> additionalContacts;
public ContactManager(IntPtr rootName, ISite[] currentSites, string ownerProtocol)
{
siteContacts = new List<ContactContainer>();
this.rootName = rootName;
mode = StatusModes.OnThePhone;
additionalContacts = new Dictionary<string, ISite>();
forkContacts = new List<ContactContainer>();
pOwner = new SettingOwner("Protocol");
mpOwner = new SettingOwner(ownerProtocol);
clOwner = new SettingOwner("CList");
sOwner = new SettingOwner("xJuickSite");
List<string> mainContacts = new List<string>();
for (int i = 0, iCount = currentSites.Length; i < iCount; i++)
{
mainContacts.Add(currentSites[i].MainContact);
ISite site = currentSites[i];
for (int j = 0, jCount = currentSites[i].AdditionalContacts.Length; j < jCount; j++)
{
additionalContacts[currentSites[i].AdditionalContacts[j]] = site;
}
}
if (!FillContactList(mainContacts, ownerProtocol))
throw new Exception("No protocols found");
addAsTemporary = false;
MirandaContext.Current.MirandaDatabase.ContactDeleted += MirandaDatabase_ContactDeleted;
}
private bool MirandaDatabase_ContactDeleted(object sender, MirandaContactEventArgs e)
{
int deleteIndex = -1;
for (int i = 0, iCount = forkContacts.Count; i < iCount; i++)
{
if (forkContacts[i].Contact.MirandaHandle == e.ContactInfo.MirandaHandle)
{
if (IsAdditional(forkContacts[i].Contact.UniqueID.ToString()))
return false;
deleteIndex = i;
break;
}
}
if (deleteIndex != -1)
{
CopyHistory(e.ContactInfo.MirandaHandle, GetMainContactHandle(e.ContactInfo.MirandaHandle), null);
forkContacts.RemoveAt(deleteIndex);
}
return false;
}
public bool IsMainContact(IntPtr hMainContact)
{
return GetMainContactContainer(hMainContact) != null;
}
private ContactContainer GetMainContactContainer(IntPtr hMainContact)
{
for (int i = 0, iCount = siteContacts.Count; i < iCount; i++)
{
if (hMainContact == siteContacts[i].Contact.MirandaHandle)
return siteContacts[i];
}
return null;
}
public IntPtr GetMainContactHandle(IntPtr childHContact)
{
ISite site = SitesManager.GetContactSite(childHContact);
if (site == null)
return IntPtr.Zero;
for (int i = 0, iCount = siteContacts.Count; i < iCount; i++)
{
if (siteContacts[i].Contact.UniqueID.ToString() == site.MainContact)
{
return siteContacts[i].Contact.MirandaHandle;
}
}
return IntPtr.Zero; // yeah. maybe will implement multi-juick later :)
}
private bool FillContactList(List<string> mainContacts, string ownerProtocol)
{
// quiet unload
if (Util.EnumProtocols().Count == 0)
return false;
Dictionary<string, Dictionary<string, ContactInfo>> protocols = new Dictionary<string, Dictionary<string, ContactInfo>>();
int contactsCount = 0;
IEnumerable<IntPtr> hContacts = MirandaContext.Current.MirandaDatabase.GetContactHandles();
foreach (IntPtr hContact in hContacts)
{
contactsCount++;
ContactInfo ci = ContactInfo.FromHandle(hContact);
if (ci == null || ci.UniqueID == null)
continue;
string jid = ci.UniqueID.ToString();
bool isAdditional = IsAdditional(jid);
if (jid.StartsWith(namePrefix) || isAdditional)
{
if (!IsOnContact(ci.MirandaHandle))
AddToContact(ci.MirandaHandle);
forkContacts.Add(new ContactContainer(this, ci));
string contactSite = (string)ci.ReadSetting(xJuickSiteField, sOwner, DatabaseSettingType.AsciiString);
if (!String.IsNullOrEmpty(contactSite))
{
ISite contactSiteObject = SitesManager.GetContactSite(contactSite, true);
if (contactSiteObject != null)
SitesManager.SitesInfo[ci.MirandaHandle] = contactSiteObject;
}
else if (isAdditional)
{
SitesManager.SitesInfo[ci.MirandaHandle] = additionalContacts[jid];
}
}
else if (mainContacts.IndexOf(jid) != -1)
{
ISite site = SitesManager.GetContactSite(jid, false);
if (site != null)
SitesManager.SitesInfo[hContact] = site;
string ownerProto = (string)ci.ReadSetting("p", pOwner, DatabaseSettingType.AsciiString);
if (!protocols.ContainsKey(jid))
protocols[jid] = new Dictionary<string, ContactInfo>();
protocols[jid].Add(ownerProto, ci);
}
}
if (contactsCount == 0)
return false;
bool found = false;
foreach (KeyValuePair<string, Dictionary<string, ContactInfo>> jp in protocols)
{
foreach (KeyValuePair<string, ContactInfo> p in jp.Value)
{
if (p.Key.Equals(ownerProtocol, StringComparison.InvariantCultureIgnoreCase))
{
this.ownerProtocol = ownerProtocol;
ContactInfo ci = jp.Value[this.ownerProtocol];
ContactContainer mainContact = new ContactContainer(this, ci);
siteContacts.Add(mainContact);
if (!IsOnContact(ci.MirandaHandle))
AddToContact(ci.MirandaHandle);
found = true;
}
}
}
if (found)
return true;
if (String.IsNullOrEmpty(this.ownerProtocol))
{
if (protocols.Count == 0)
{
System.Windows.Forms.MessageBox.Show("Found ZERO protocols with main accounts (check options)" + Environment.NewLine +
"xJuick plugin will be unloaded now.", "[xJuick] Jabber Protocol error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
/*ProtocolSelect ps = new ProtocolSelect(protocols);
if (ps.ShowDialog() != DialogResult.OK)
return false;
if (String.IsNullOrEmpty(ps.ResultProtocol) || ps.ResultContactInfo == null)
return false;
this.ownerProtocol = ps.ResultProtocol;
ContactInfo ci = ps.ResultContactInfo;
ContactContainer mainContact = new ContactContainer(this, ci);
siteContacts.Add(mainContact);
if (!IsOnContact(ci.MirandaHandle))
AddToContact(ci.MirandaHandle);
Settings.Instance.JabberProtocolName = this.ownerProtocol;
Settings.Save();*/
return true;
}
return false;
}
public bool IsForked(IntPtr hContact)
{
for (int i = 0, iCount = forkContacts.Count; i < iCount; i++)
{
if (forkContacts[i].Contact.MirandaHandle == hContact)
{
return true;
}
}
return false;
}
public bool IsAdditional(string UID)
{
return additionalContacts.ContainsKey(UID);
}
public ContactInfo GetContactInfo(string mainContact, string name)
{
ContactInfo result = null;
string sname = namePrefix + name;
for (int i = 0, iCount = forkContacts.Count; i < iCount; i++)
{
if (forkContacts[i].Contact != null && forkContacts[i].Contact.UniqueID != null)
{
if (forkContacts[i].Contact.UniqueID.ToString().Equals(sname, StringComparison.InvariantCultureIgnoreCase))
{
result = forkContacts[i].Contact;
break;
}
}
else
{
MessageBox.Show("GetContactInfo() -> Null ID [???]");
}
}
if (result == null && Settings.Instance.AutoFork)
{
result = MakeFork(mainContact, name);
}
else if (result != null)
ChangeStatus(result, mode);
return result;
}
private ContactInfo MakeFork(string mainContact, string name)
{
ContactInfo result = AddNewContact(mainContact, name);
if (result != null)
{
SitesManager.SitesInfo[result.MirandaHandle] = SitesManager.GetContactSite(mainContact, false);
if (!IsOnContact(result.MirandaHandle))
AddToContact(result.MirandaHandle);
forkContacts.Add(new ContactContainer(this, result));
ChangeStatus(result, mode);
}
return result;
}
public void CopyHistory(IntPtr fromContact, IntPtr toContact, Regex condition)
{
MirandaDB.DirectCopyHistory(fromContact, toContact, condition);
}
public void SettingsChanged()
{
for (int i = 0, iCount = siteContacts.Count; i < iCount; i++)
{
if (siteContacts[i].Processor != null)
siteContacts[i].Processor.SettingsChanged();
}
for (int i = 0, iCount = forkContacts.Count; i < iCount; i++)
{
if (forkContacts[i].Processor != null)
{
forkContacts[i].Processor.SettingsChanged();
break;
}
}
}
public void OpenChat(IntPtr hContact, IntPtr hWnd)
{
ContactContainer contact = GetMainContactContainer(hContact);
ISite site = SitesManager.GetContactSite(hContact);
if (site == null)
{
if (contact != null)
{
string cintactID = contact.Contact.UniqueID.ToString();
site = SitesManager.GetContactSite(cintactID, true);
if (site != null)
SitesManager.SitesInfo[hContact] = site;
}
else
{
ContactInfo ci = ContactInfo.FromHandle(hContact);
string contactSite = (string)ci.ReadSetting(xJuickSiteField, pOwner, DatabaseSettingType.AsciiString);
if (!String.IsNullOrEmpty(contactSite))
{
site = SitesManager.GetContactSite(contactSite, false);
}
else if (IsAdditional(ci.UniqueID.ToString()))
{
site = additionalContacts[ci.UniqueID.ToString()];
}
}
if (site == null)
return;
}
if (contact != null)
{
contact.InitMessageProcessor(site, hContact, hWnd);
return;
}
for (int i = 0, iCount = forkContacts.Count; i < iCount; i++)
{
if (forkContacts[i].Contact.MirandaHandle == hContact)
{
forkContacts[i].InitMessageProcessor(site, hContact, hWnd);
break;
}
}
}
public void CloseChat(IntPtr hContact)
{
//SitesManager.SitesInfo.Remove(hContact);
ContactContainer contact = GetMainContactContainer(hContact);
if (contact != null)
{
contact.Close();
return;
}
for (int i = 0, iCount = forkContacts.Count; i < iCount; i++)
{
if (forkContacts[i].Contact.MirandaHandle == hContact)
{
forkContacts[i].Close();
break;
}
}
}
public void ProcessHistoryItem(IntPtr smallHandle, ItemRenderDetails ird)
{
ContactContainer item = null;
ContactContainer contact = GetMainContactContainer(ird.hContact);
if (contact != null)
{
item = contact;
}
else
{
for (int i = 0, iCount = forkContacts.Count; i < iCount; i++)
{
if (forkContacts[i].Contact.MirandaHandle == ird.hContact)
{
item = forkContacts[i];
break;
}
}
}
if (item == null)
return;
if (item.Processor is HistoryppHandler)
((HistoryppHandler)item.Processor).ProcessHistoryItem(smallHandle, ird);
}
public void Avatars()
{
for (int i = 0, iCount = siteContacts.Count; i < iCount; i++)
{
if (siteContacts[i].Processor != null)
siteContacts[i].Processor.Avatars();
}
for (int i = 0, iCount = forkContacts.Count; i < iCount; i++)
{
if (forkContacts[i].Processor != null)
forkContacts[i].Processor.Avatars();
}
}
public void Update(IntPtr hContact)
{
ContactContainer contact = GetMainContactContainer(hContact);
if (contact != null)
{
contact.UpdateProcessor();
return;
}
for (int i = 0, iCount = forkContacts.Count; i < iCount; i++)
{
if (forkContacts[i].Contact.MirandaHandle == hContact)
{
forkContacts[i].UpdateProcessor();
break;
}
}
}
private ContactInfo AddNewContact(string mainContact, string uid)
{
if (String.IsNullOrEmpty(ownerProtocol))
return null;
try
{
ContactInfo ci = ContactInfo.CreateContact();
ci.WriteSetting("FullName", mpOwner, uid, DatabaseSettingType.AsciiString);
ci.WriteSetting("jid", mpOwner, namePrefix + uid, DatabaseSettingType.AsciiString);
ci.WriteSetting("p", pOwner, ownerProtocol, DatabaseSettingType.AsciiString);
ci.WriteSetting(xJuickSiteField, sOwner, mainContact, DatabaseSettingType.AsciiString);
if (addAsTemporary)
{
ci.WriteSetting("NotOnList", clOwner, 1, DatabaseSettingType.Byte);
ci.WriteSetting("Delete", clOwner, 1, DatabaseSettingType.Byte);
}
return ci;
}
catch (Exception ex)
{
/*QuickDebug qd = new QuickDebug(ex.Message + Environment.NewLine + ex.StackTrace);
qd.ShowDialog();*/
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace);
return null;
}
}
public ContactInfo CheckForHandle(IntPtr hContact, string message)
{
Match m = Regexps.ReplyRegEx.Match(message);
if (m.Success)
{
string mainContact = SitesManager.GetContactSite(hContact).MainContact;
return GetContactInfo(mainContact, "#" + m.Groups["post"].Value);
}
return null;
}
public ContactInfo CheckForHandlePure(IntPtr hContact, string message)
{
Match m = Regexps.PureReplyRegEx.Match(message);
if (m.Success)
{
ISite site = SitesManager.GetContactSite(hContact);
string mainContact = site == null ? String.Empty : site.MainContact;
return GetContactInfo(mainContact, "#" + m.Groups["post"].Value);
}
return null;
}
public void ChangeForkState(IntPtr hContact, string name)
{
string mainContact = SitesManager.GetContactSite(hContact).MainContact;
ContactInfo result = GetContactInfo(mainContact, name);
if (result == null)
{
result = MakeFork(mainContact, name);
if (result != null)
CopyHistory(GetMainContactHandle(hContact), result.MirandaHandle, Regexps.GetHistoryRegEx(name));
}
else
{
result.OpenMessageWindow();
}
}
private void AddToContact(IntPtr hContact)
{
MirandaContext.Current.CallService(API.MS_PROTO_ADDTOCONTACT, hContact, rootName);
}
private bool IsOnContact(IntPtr hContact)
{
return Convert.ToBoolean(MirandaContext.Current.CallService(API.MS_PROTO_ISPROTOONCONTACT, hContact, rootName));
}
private void ChangeStatus(ContactInfo ci, StatusModes status)
{
try
{
ci.WriteSetting("Status", mpOwner, (UInt16)status, DatabaseSettingType.UInt16);
}
catch { }
}
public void ClearContacts()
{
ContactContainer[] fk = forkContacts.ToArray();
for (int i = 0, iCount = fk.Length; i < iCount; i++)
{
if (!IsAdditional(fk[i].Contact.UniqueID.ToString()))
{
fk[i].Contact.Delete();
}
}
forkContacts.Clear();
forkContacts = new List<ContactContainer>();
}
public void OnJuickClicked(object sender, ActionClickEvent e)
{
IntPtr hContact = ((ContactContainer) sender).Contact.MirandaHandle;
if (!e.AutoSend)
{
UnmanagedStringHandle str = new UnmanagedStringHandle(e.Action, StringEncoding.Ansi);
MirandaContext.Current.CallService(API.MS_MSG_SENDMESSAGE, hContact, str.IntPtr);
str.Free();
}
else
{
if (e.Action.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase))
{
Util.OpenURL(e.Action);
}
else if (e.Action.StartsWith("xJuick://", StringComparison.InvariantCultureIgnoreCase))
{
InvokeOnAction(hContact, e.Action.Substring(9).ToLower());
}
else
{
CSSData css = new CSSData();
css.hContact = hContact; //juickContact.Contact.MirandaHandle;
css.szProtoService = API.PSS_MESSAGE;
css.wParam = IntPtr.Zero;
css.lParam = new UnmanagedStringHandle(e.Action, StringEncoding.Ansi).IntPtr;
IntPtr cmdPtr = Marshal.AllocHGlobal(Marshal.SizeOf(css));
Marshal.StructureToPtr(css, cmdPtr, false);
MirandaContext.Current.CallService(API.MS_PROTO_CALLCONTACTSERVICE, IntPtr.Zero, cmdPtr);
}
}
}
public event EventHandler<ActionEvent> OnAction;
public void InvokeOnAction(IntPtr hContact, string action)
{
if (OnAction == null)
return;
OnAction(this, new ActionEvent(hContact, action));
}
public void Dispose()
{
for (int i = 0, iCount = forkContacts.Count; i < iCount; i++)
{
forkContacts[i].Dispose();
}
}
}
}