mit hyphen

This commit is contained in:
2013-06-25 22:53:41 +00:00
parent 8896edc368
commit 318d93e6c1
424 changed files with 161843 additions and 2 deletions
@@ -0,0 +1,63 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
internal class CallbackWrapper
{
#region Properties
private string serviceName;
public string ServiceName
{
get { return serviceName; }
protected set { serviceName = value; }
}
#endregion
#region .ctors
private CallbackWrapper(string serviceName)
{
if (String.IsNullOrEmpty(serviceName))
throw new ArgumentNullException("serviceName");
this.serviceName = serviceName;
}
public static Callback Create(string serviceName)
{
return new Callback(new CallbackWrapper(serviceName).Callback);
}
#endregion
#region Methods
protected int Callback(UIntPtr wParam, IntPtr lParam)
{
return MirandaContext.Current.CallService(ServiceName, wParam, lParam);
}
#endregion
}
}
@@ -0,0 +1,33 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[Serializable]
public class ConfigurationException : Exception
{
public ConfigurationException() { }
public ConfigurationException(string message) : base(message) { }
public ConfigurationException(string message, Exception inner) : base(message, inner) { }
protected ConfigurationException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
}
@@ -0,0 +1,102 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Configuration;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class ConfigurationOptionsAttribute : Attribute
{
#region .ctors
internal ConfigurationOptionsAttribute() { }
public ConfigurationOptionsAttribute(string configurationVersion) : this(configurationVersion, false, true) { }
[Obsolete("Will be removed in future. Use named arguments instead.", true)]
public ConfigurationOptionsAttribute(bool encrypt, bool profileBound) : this(null, encrypt, profileBound) { }
[Obsolete("Will be removed in future. Use named arguments instead.", false)]
public ConfigurationOptionsAttribute(string configurationVersion, bool encrypt, bool profileBound)
{
if (!String.IsNullOrEmpty(configurationVersion))
this.version = new Version(configurationVersion);
this.encrypt = encrypt;
this.profileBound = profileBound;
}
#endregion
#region Properties
private readonly Version version;
public Version Version
{
get { return version; }
}
private bool profileBound;
public bool ProfileBound
{
get { return profileBound; }
set { profileBound = value; }
}
private bool encrypt;
public bool Encrypt
{
get { return encrypt; }
set { encrypt = value; }
}
private Type storage;
public Type Storage
{
get { return storage; }
set { storage = value; }
}
private Type encryption;
public Type Encryption
{
get { return encryption; }
set { encryption = value; }
}
#endregion
#region Methods
internal ConfigurationOptionsAttribute Finalize()
{
if (storage == null)
storage = typeof(IsolatedStorage);
if (encrypt && encryption == null)
encryption = typeof(WindowsEncryption);
return this;
}
#endregion
}
}
@@ -0,0 +1,753 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Virtuoso.Hyphen;
using Virtuoso.Miranda.Plugins.Resources;
using System.Runtime.Serialization;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[Serializable]
public class ContactInfo : MirandaItem, ISerializable
{
#region Enums
[Flags]
private enum ContactDisplayNameOptions : int
{
/// <summary>
/// Will return char*, as usual.
/// </summary>
Ansi = 0,
/// <summary>
/// Will never return the user's custom name.
/// </summary>
NoMyHandle = 1,
/// <summary>
/// Will return TCHAR* instead of char*.
/// </summary>
Unicode = 2,
/// <summary>
/// Will not use the cache.
/// </summary>
NoCache = 4
}
#endregion
#region Contants
private const string MS_DB_CONTACT_IS = "DB/Contact/Is",
MS_PROTO_GETCONTACTBASEPROTO = "Proto/GetContactBaseProto",
MS_DB_CONTACT_WRITESETTING = "DB/Contact/WriteSetting",
MS_DB_CONTACT_GETSETTING = "DB/Contact/GetSetting",
MS_DB_CONTACT_GETSETTINGSTATIC = "DB/Contact/GetSettingStatic",
MS_DB_CONTACT_DELETESETTING = "DB/Contact/DeleteSetting",
MS_DB_CONTACT_ADD = "DB/Contact/Add",
MS_DB_CONTACT_DELETE = "DB/Contact/Delete",
MS_CLIST_GETCONTACTDISPLAYNAME = "CList/GetContactDisplayName",
SETTING_STATUS = "Status",
MS_MSG_SENDMESSAGE = "SRMsg/SendCommand",
MS_MSG_SENDMESSAGE_2 = "SRMsg/LaunchMessageWindow";
#endregion
#region Fields
private static readonly object SyncObject = new object();
private static readonly ContactInfo meNeutral = new ContactInfo();
private readonly Protocol owningModule;
private object value;
private ContactInfoPropertyType valueType;
#endregion
#region .ctors
private ContactInfo()
: base(IntPtr.Zero, ItemType.Contact)
{
this.owningModule = Protocol.UnknownProtocol;
}
protected ContactInfo(SerializationInfo info, StreamingContext context)
: this((IntPtr)info.GetInt64("MirandaHandle"))
{
}
[CLSCompliant(false), Obsolete("Will be removed in the future, use FromHandle(UIntPtr) instead.")]
public ContactInfo(UIntPtr contactHandle) : this(Translate.ToHandle(contactHandle)) { }
[Obsolete("Will be removed in the future, use FromHandle(IntPtr) instead.")]
public ContactInfo(IntPtr contactHandle)
: base(contactHandle, ItemType.Contact)
{
MirandaContext context = MirandaContext.Current;
if (contactHandle != IntPtr.Zero && context.CallService(MS_DB_CONTACT_IS, contactHandle, IntPtr.Zero) == 0)
throw new ArgumentException("Contact not found in Miranda database.");
IntPtr protoNamePtr = GetModuleNamePtr(contactHandle);
if (protoNamePtr != IntPtr.Zero)
{
string protoName = Translate.ToString(protoNamePtr, StringEncoding.Ansi);
MirandaContext.Current.Protocols.TryGetValue(protoName, out owningModule);
}
if (owningModule == null)
{
owningModule = Protocol.UnknownProtocol;
if (contactHandle != IntPtr.Zero)
Log.DebuggerWrite(5, Loader.LogCategory, "Unable to obtain contact's protocol");
}
this.MirandaHandle = contactHandle;
}
public static ContactInfo FromHandle(IntPtr contactHandle)
{
return new ContactInfo(contactHandle);
}
[CLSCompliant(false)]
public static ContactInfo FromHandle(UIntPtr contactHandle)
{
return new ContactInfo(contactHandle);
}
#endregion
#region Properties
public ContactInfoPropertyType PropertyType
{
get { return valueType; }
}
public object PropertyValue
{
get { return this.value; }
}
public Protocol OwningModule
{
get { return owningModule; }
}
public bool IsSelf
{
get
{
return (MirandaHandle == IntPtr.Zero);
}
}
public static ContactInfo MeNeutral
{
get
{
return meNeutral;
}
}
public StatusMode? Status
{
get
{
if (String.IsNullOrEmpty(OwningModule.Name))
return null;
object obj = ReadSetting(SETTING_STATUS, DatabaseSettingType.UInt16);
if (obj != null)
return (StatusMode)(UInt16)obj; //(StatusMode)Enum.Parse(typeof(StatusMode), (Int16) obj);
else
return null;
}
}
public string DisplayName
{
get
{
return GetDisplayName(MirandaHandle);
}
}
private object uniqueID;
public object UniqueID
{
get
{
lock (SyncObject)
{
if (uniqueID == null)
{
ContactInfoPropertyType type;
GetUniqueID(MirandaHandle, out uniqueID, out type);
}
return uniqueID;
}
}
}
#endregion
#region Methods
#region Settings/Write
public bool WriteSetting(string name, object value, DatabaseSettingType saveAs)
{
return WriteSetting(name, OwningModule, value, saveAs);
}
public bool WriteSetting(string name, ISettingOwner owner, object value, DatabaseSettingType saveAs)
{
if (owner == null)
throw new ArgumentNullException("owner");
return WriteSetting(name, owner.Name, value, saveAs);
}
public bool WriteSettingAsBlob(string name, ISettingOwner owner, byte[] blob)
{
if (owner == null)
throw new ArgumentNullException("owner");
return WriteSettingAsBlob(name, owner.Name, blob);
}
public bool WriteSettingAsBlob(string name, string owner, byte[] blob)
{
if (blob == null)
throw new ArgumentNullException("blob");
throw new NotImplementedException();
//return WriteSetting(name, owner, blob, DatabaseSettingType.Blob);
}
public unsafe bool WriteSetting(string name, string owner, object value, DatabaseSettingType saveAs)
{
if (String.IsNullOrEmpty(owner))
throw new ArgumentNullException("owner");
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
UnmanagedStringHandle valueHandle = UnmanagedStringHandle.Empty;
UnmanagedStringHandle nameHandle = Translate.ToHandle(name, StringEncoding.Ansi);
UnmanagedStringHandle moduleNameHandle = Translate.ToHandle(owner, StringEncoding.Ansi);
IntPtr blobPtr = IntPtr.Zero;
try
{
DBCONTACTWRITESETTING dbSetting = new DBCONTACTWRITESETTING();
dbSetting.Name = nameHandle;
dbSetting.Module = moduleNameHandle;
dbSetting.Value = new DBVARIANT();
dbSetting.Value.Type = (byte)saveAs;
switch (saveAs)
{
case DatabaseSettingType.AsciiString:
valueHandle = new UnmanagedStringHandle(value.ToString(), StringEncoding.Ansi);
dbSetting.Value.Text.TextPtr = valueHandle.IntPtr;
break;
case DatabaseSettingType.UnicodeString:
case DatabaseSettingType.UTF8String:
valueHandle = new UnmanagedStringHandle(value.ToString(), StringEncoding.Unicode);
dbSetting.Value.Text.TextPtr = valueHandle.IntPtr;
break;
case DatabaseSettingType.Byte:
dbSetting.Value.Primitives.Byte = Convert.ToByte(value);
break;
case DatabaseSettingType.UInt16:
dbSetting.Value.Primitives.Word = Convert.ToUInt16(value);
break;
case DatabaseSettingType.UInt32:
dbSetting.Value.Primitives.DWord = Convert.ToUInt32(value);
break;
case DatabaseSettingType.Blob:
throw new NotImplementedException();
/*byte[] blob = value as byte[];
if (blob == null)
throw new ArgumentException("value");
blobPtr = Marshal.AllocHGlobal(blob.Length);
Marshal.Copy(blob, 0, blobPtr, blob.Length);
dbSetting.Value.Blob.BlobPtr = blobPtr;
dbSetting.Value.Blob.Size = (UInt16)blob.Length;
break;*/
default:
throw new ArgumentOutOfRangeException("saveAs");
}
bool result = MirandaContext.Current.CallServiceUnsafe(MS_DB_CONTACT_WRITESETTING, MirandaHandle.ToPointer(), &dbSetting) == 0;
Debug.Assert(result);
return result;
}
catch (FormatException fE)
{
throw new ArgumentOutOfRangeException("value", fE);
}
catch (Exception e)
{
throw new MirandaException(TextResources.ExceptionMsg_ErrorWhileCallingMirandaService, e);
}
finally
{
valueHandle.Free();
nameHandle.Free();
moduleNameHandle.Free();
if (blobPtr != IntPtr.Zero)
Marshal.FreeHGlobal(blobPtr);
}
}
#endregion
#region Settings/Read
public object ReadSetting(string name, DatabaseSettingType readAs)
{
return ReadSetting(MirandaHandle, name, readAs);
}
public static object ReadSetting(IntPtr contactHandle, string name, DatabaseSettingType readAs)
{
IntPtr pOwnerName = GetModuleNamePtr(contactHandle);
if (pOwnerName == IntPtr.Zero)
throw new InvalidOperationException(TextResources.ExceptionMsg_OwnerUnknown);
return ReadSetting(contactHandle, name, Marshal.PtrToStringAnsi(pOwnerName), readAs);
}
public object ReadSetting(string name, ISettingOwner owner, DatabaseSettingType readAs)
{
return ReadSetting(MirandaHandle, name, owner, readAs);
}
public static object ReadSetting(IntPtr contactHandle, string name, ISettingOwner owner, DatabaseSettingType readAs)
{
if (owner == null)
throw new ArgumentNullException("owner");
return ReadSetting(contactHandle, name, owner.Name, readAs);
}
public object ReadSetting(string name, string owner, DatabaseSettingType readAs)
{
return ReadSetting(MirandaHandle, name, owner, readAs);
}
public static object ReadSetting(IntPtr contactHandle, string name, string owner, DatabaseSettingType readAs)
{
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
InteropBuffer buffer = InteropBufferPool.AcquireBuffer();
try
{
DBCONTACTGETSETTING dbSetting = new DBCONTACTGETSETTING();
dbSetting.Name = name;
DBVARIANT dbVariant = new DBVARIANT();
dbVariant.Type = (byte)readAs;
buffer.Lock();
if (readAs != DatabaseSettingType.Blob)
{
dbVariant.Text.TextPtr = buffer.IntPtr;
dbVariant.Text.TextBufferSize = (ushort)buffer.Size;
}
else
{
throw new NotImplementedException();
//dbVariant.Blob.BlobPtr = buffer.IntPtr;
}
return ReadSettingInternal(contactHandle, owner, ref dbSetting, ref dbVariant);
}
catch (Exception e)
{
throw new MirandaException(TextResources.ExceptionMsg_ErrorWhileCallingMirandaService, e);
}
finally
{
buffer.Unlock();
InteropBufferPool.ReleaseBuffer(buffer);
}
}
private static object ReadSettingInternal(IntPtr contactHandle, string owner, ref DBCONTACTGETSETTING setting, ref DBVARIANT variant)
{
UnmanagedStructHandle<DBCONTACTGETSETTING> dbSettingHandle = UnmanagedStructHandle<DBCONTACTGETSETTING>.Empty;
UnmanagedStructHandle<DBVARIANT> dbVariantHandle = UnmanagedStructHandle<DBVARIANT>.Empty;
try
{
dbVariantHandle = new UnmanagedStructHandle<DBVARIANT>(ref variant);
setting.Module = owner;
setting.DbVariantPtr = dbVariantHandle.IntPtr;
dbSettingHandle = new UnmanagedStructHandle<DBCONTACTGETSETTING>(ref setting);
int result = MirandaContext.Current.CallService(MS_DB_CONTACT_GETSETTINGSTATIC, contactHandle, dbSettingHandle.IntPtr);
Debug.Assert(result != 2, "Deleted setting encountered");
if (result != 0)
return null;
dbVariantHandle.MarshalBack(out variant);
return Translate.ValueFromVariant(ref variant);
}
finally
{
dbVariantHandle.Free();
dbSettingHandle.Free();
}
}
#endregion
#region Settings/Delete
public bool DeleteSetting(string name, ISettingOwner owner)
{
if (owner == null)
throw new ArgumentNullException("owner");
return DeleteSetting(name, owner.Name);
}
public bool DeleteSetting(string name, string owner)
{
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
if (String.IsNullOrEmpty(owner))
throw new ArgumentNullException("owner");
DBCONTACTGETSETTING dbGetSetting = new DBCONTACTGETSETTING();
dbGetSetting.Name = name;
dbGetSetting.Module = owner;
UnmanagedStructHandle<DBCONTACTGETSETTING> dbSettingHandle = new UnmanagedStructHandle<DBCONTACTGETSETTING>(ref dbGetSetting);
try
{
return MirandaContext.Current.CallService(MS_DB_CONTACT_DELETESETTING, MirandaHandle, dbSettingHandle.IntPtr) == 0;
}
finally
{
dbSettingHandle.Free();
}
}
#endregion
#region Converters
public static TId[] GetUniqueIDs<TId>(params ContactInfo[] contacts)
{
if (contacts == null)
throw new ArgumentNullException("contacts");
if (contacts.Length == 0)
return new TId[0];
return Array.ConvertAll<ContactInfo, TId>(contacts, delegate(ContactInfo contact)
{
if (contact != null)
return contact.UniqueIdAs<TId>();
else
return default(TId);
});
}
public static string[] GetDisplayNames(params string[] uuids)
{
if (uuids == null)
throw new ArgumentNullException("uuids");
if (uuids.Length == 0)
return new string[0];
return Array.ConvertAll<string, string>(uuids, delegate(string uuid)
{
if (uuid == null)
return null;
ContactInfo contact = MirandaContext.Current.MirandaDatabase.FindContact(uuid);
if (contact != null)
return contact.DisplayName;
else
return null;
});
}
#endregion
#region Helpers
private static IntPtr GetModuleNamePtr(IntPtr contactHandle)
{
return (IntPtr)MirandaContext.Current.CallService(MS_PROTO_GETCONTACTBASEPROTO, contactHandle, IntPtr.Zero);
}
public static string GetDisplayName(IntPtr contactHandle)
{
ContactDisplayNameOptions options = ContactDisplayNameOptions.Unicode;
IntPtr pName = (IntPtr)MirandaContext.Current.CallService(MS_CLIST_GETCONTACTDISPLAYNAME, contactHandle, (IntPtr)options);
if (pName == IntPtr.Zero)
return null;
else
return Translate.ToString(pName, StringEncoding.Unicode);
}
public static bool GetUniqueID(IntPtr contactHandle, out object uuid, out ContactInfoPropertyType uuidType)
{
return GetProperty(contactHandle, ContactInfoProperty.UniqueID, out uuid, out uuidType);
}
public static bool GetProperty(IntPtr contactHandle, ContactInfoProperty property, out object value, out ContactInfoPropertyType valueType)
{
CONTACTINFO contactInfo = new CONTACTINFO(contactHandle, GetModuleNamePtr(contactHandle));
contactInfo.Flag = (byte)((byte)property | (byte)ContactInfoPropertyFlags.Unicode);
unsafe
{
int result = MirandaContext.Current.CallServiceUnsafe(MirandaServices.MS_CONTACT_GETCONTACTINFO, null, &contactInfo);
if (result != 0)
{
value = null;
valueType = ContactInfoPropertyType.Unknown;
return false;
}
}
switch (valueType = (ContactInfoPropertyType)contactInfo.Type)
{
case ContactInfoPropertyType.Byte:
value = Convert.ToByte(contactInfo.Value.ToInt32());
break;
case ContactInfoPropertyType.String:
value = Translate.ToString(contactInfo.Value, StringEncoding.Unicode);
break;
case ContactInfoPropertyType.UInt16:
value = Convert.ToUInt16(contactInfo.Value.ToInt32());
break;
case ContactInfoPropertyType.UInt32:
value = contactInfo.Value.ToInt32();
break;
default:
value = null;
valueType = ContactInfoPropertyType.Unknown;
return false;
}
return true;
}
#endregion
#region ISerializable Members
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("MirandaHandle", MirandaHandle.ToInt64());
}
#endregion
public TId UniqueIdAs<TId>()
{
object uuid = UniqueID;
return uuid == null ? default(TId) : (TId)Convert.ChangeType(uuid, typeof(TId));
}
public override string ToString()
{
return !Protocol.UnknownProtocol.Equals(OwningModule) ?
String.Format("{0} ({1})", DisplayName, OwningModule.Name) : DisplayName;
}
public static bool operator ==(ContactInfo first, ContactInfo second)
{
if (object.ReferenceEquals(first, second))
return true;
else if (object.ReferenceEquals(first, null))
return false;
else
return first.Equals(second);
}
public static bool operator !=(ContactInfo first, ContactInfo second)
{
return !(first == second);
}
public override bool Equals(object obj)
{
ContactInfo other = obj as ContactInfo;
if (object.ReferenceEquals(other, null))
return false;
else
return GetHashCode() == other.GetHashCode();
}
public override int GetHashCode()
{
return MirandaHandle.ToInt32();
}
public static ContactInfo CreateContact()
{
IntPtr hContact = (IntPtr)MirandaContext.Current.CallService(MS_DB_CONTACT_ADD);
if (hContact == IntPtr.Zero)
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MS_DB_CONTACT_ADD, hContact.ToString()));
return ContactInfo.FromHandle(hContact);
}
public bool Delete()
{
if (IsSelf)
throw new InvalidOperationException();
return (0 == MirandaContext.Current.CallService(MS_DB_CONTACT_DELETE, MirandaHandle, IntPtr.Zero));
}
public bool GetProperty(ContactInfoProperty property, StringEncoding stringEncoding)
{
return GetProperty(MirandaHandle, property, out value, out valueType);
}
public int CallContactService(string serviceName)
{
return CallContactService(serviceName, UIntPtr.Zero, IntPtr.Zero);
}
[CLSCompliant(false)]
public int CallContactService(string serviceName, UIntPtr wParam, IntPtr lParam)
{
if (serviceName == null)
throw new ArgumentNullException("serviceName");
CCSDATA ccsData = new CCSDATA(this, serviceName);
ccsData.WParam = wParam;
ccsData.LParam = lParam;
try
{
unsafe
{
return MirandaContext.Current.CallServiceUnsafe(MirandaServices.MS_PROTO_CALLCONTACTSERVICE, null, &ccsData);
}
}
finally
{
ccsData.Free();
}
}
public void SendMessage(string message)
{
if (message == null)
throw new ArgumentNullException("message");
UnmanagedStringHandle nativeHandle = UnmanagedStringHandle.Empty;
try
{
nativeHandle = new UnmanagedStringHandle(message, StringEncoding.Ansi);
CallContactService(MirandaServices.PS_MESSAGE, UIntPtr.Zero, nativeHandle.IntPtr);
}
finally
{
nativeHandle.Free();
}
}
public void OpenMessageWindow()
{
OpenMessageWindow(null);
}
public void OpenMessageWindow(string message)
{
UnmanagedStringHandle messageHandle = UnmanagedStringHandle.Empty;
try
{
if (!String.IsNullOrEmpty(message))
messageHandle = new UnmanagedStringHandle(message, StringEncoding.Ansi);
int result = (int)CallbackResult.Success;
if (result != MirandaContext.Current.CallService(MS_MSG_SENDMESSAGE, MirandaHandle, messageHandle.IntPtr))
if ((int)CallbackResult.Success != (result = MirandaContext.Current.CallService(MS_MSG_SENDMESSAGE_2, MirandaHandle, messageHandle.IntPtr)))
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MS_MSG_SENDMESSAGE, result.ToString()));
}
finally
{
messageHandle.Free();
}
}
#endregion
}
}
@@ -0,0 +1,49 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public enum ContactInfoProperty : byte
{
// Types of information you can retreive by setting the dwFlag in CONTACTINFO
FirstName = 1, // returns first eventName (string)
LastName = 2, // returns last eventName (string)
Nick = 3, // returns nick eventName (string)
CustomNick = 4, // returns custom nick name, clist name (string)
Email = 5, // returns email (string)
City = 6, // returns city (string)
State = 7, // returns state (string)
Country = 8, // returns country (string)
Phone = 9, // returns phone (string)
HomePage = 10, // returns homepage (string)
About = 11, // returns about info (string)
Gender = 12, // returns gender (byte,'M','F' character)
Age = 13, // returns age (byte, 0==unspecified)
FirstAndLastName = 14, // returns first eventName + last eventName (string)
UniqueID = 15, // returns uniqueid, protocol username (must check type for type of return)
}
[Flags]
internal enum ContactInfoPropertyFlags : byte
{
Unicode = 0x80,
}
}
@@ -0,0 +1,503 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using Virtuoso.Miranda.Plugins.Resources;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Drawing;
using Virtuoso.Hyphen.Mini;
using System.Windows.Forms;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public sealed class ContactList : EventPublisher
{
#region Constants
private const string ME_CLC_SHOWINFOTIP = "CLC/ShowInfoTip",
ME_CLC_HIDEINFOTIP = "CLC/HideInfoTip",
MS_CLC_SETINFOTIPHOVERTIME = "CLC/SetInfoTipHoverTime",
MS_CLC_GETINFOTIPHOVERTIME = "CLC/GetInfoTipHoverTime",
ME_CLIST_STATUSMODECHANGE = "CList/StatusModeChange",
ME_CLIST_PREBUILDCONTACTMENU = "CList/PreBuildContactMenu",
ME_CLIST_DOUBLECLICKED = "CList/DoubleClicked";
private const string MS_CLIST_ADDEVENT = "CList/AddEvent",
MS_CLIST_REMOVEEVENT = "Clist/RemoveEvent";
#endregion
#region Fields
private static readonly object SyncObject = new object();
private EventHandler<ContactListEventArgs<ContactListInfoTip>> InfoTipShowEventHandler,
InfoTipHideEventHandler;
private EventHandler<ProtocolStatusChangeEventArgs> ProtocolStatusChangeEventHandler;
private EventHandler<ContactListEventArgs<ContactInfo>> ContactMenuShowingEventHandler;
private MirandaEventHandler<ContactListEventArgs<ContactInfo>> ContactDoubleClickedEventHandler;
private bool ContactSelectionTrackingEnabled;
private ContactInfo selectedContact;
private static readonly Random Random = new Random();
#endregion
#region .ctors
internal ContactList() { }
#endregion
#region Properties
public ContactInfo SelectedContact
{
get
{
return selectedContact;
}
}
public byte? Transparency
{
get
{
object alpha = ContactInfo.MeNeutral.ReadSetting("Alpha", "CList", DatabaseSettingType.Byte);
if (alpha != null)
return (byte)alpha;
else
return null;
}
set
{
ContactInfo.MeNeutral.WriteSetting("Alpha", "CList", value.GetValueOrDefault(byte.MaxValue), DatabaseSettingType.Byte);
}
}
public bool TransparencyEnabled
{
get
{
object enabled = ContactInfo.MeNeutral.ReadSetting("Transparent", "CList", DatabaseSettingType.Byte);
if (enabled != null)
return Convert.ToBoolean((byte)enabled);
else
return false;
}
set
{
ContactInfo.MeNeutral.WriteSetting("Transparent", "CList", Convert.ToByte(value), DatabaseSettingType.Byte);
}
}
#endregion
#region Events
private void FireInfoTipEvent(EventHandler<ContactListEventArgs<ContactListInfoTip>> e, IntPtr lParam)
{
if (e == null)
return;
ContactListInfoTip infoTip = (ContactListInfoTip)Marshal.PtrToStructure(lParam, typeof(ContactListInfoTip));
ContactListEventArgs<ContactListInfoTip> eArgs = new ContactListEventArgs<ContactListInfoTip>(infoTip);
e(this, eArgs);
}
public event EventHandler<ContactListEventArgs<ContactListInfoTip>> InfoTipShow
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<EventHandler<ContactListEventArgs<ContactListInfoTip>>>(ref InfoTipShowEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_CLC_SHOWINFOTIP,
delegate(UIntPtr wParam, IntPtr lParam)
{
FireInfoTipEvent(InfoTipShowEventHandler, lParam);
return (int)CallbackResult.Success;
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<EventHandler<ContactListEventArgs<ContactListInfoTip>>>(ref InfoTipShowEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_CLC_SHOWINFOTIP, this.InfoTipShowEventHandler);
}
}
public event EventHandler<ContactListEventArgs<ContactListInfoTip>> InfoTipHide
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<EventHandler<ContactListEventArgs<ContactListInfoTip>>>(ref InfoTipHideEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_CLC_HIDEINFOTIP,
delegate(UIntPtr wParam, IntPtr lParam)
{
FireInfoTipEvent(InfoTipHideEventHandler, lParam);
return (int)CallbackResult.Success;
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<EventHandler<ContactListEventArgs<ContactListInfoTip>>>(ref InfoTipHideEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_CLC_HIDEINFOTIP, this.InfoTipHideEventHandler);
}
}
public event EventHandler<ProtocolStatusChangeEventArgs> ProtocolStatusChange
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<EventHandler<ProtocolStatusChangeEventArgs>>(ref ProtocolStatusChangeEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_CLIST_STATUSMODECHANGE,
delegate(UIntPtr wParam, IntPtr lParam)
{
string protocolName = lParam == IntPtr.Zero ? null : Translate.ToString(lParam, StringEncoding.Ansi);
Protocol protocol = null;
if (!String.IsNullOrEmpty(protocolName))
protocol = new Protocol(protocolName, ProtocolType.Protocol);
ProtocolStatusChangeEventArgs eArgs = new ProtocolStatusChangeEventArgs(protocol, Translate.ToStatus(wParam));
if (ProtocolStatusChangeEventHandler != null)
ProtocolStatusChangeEventHandler(this, eArgs);
return (int)CallbackResult.Success;
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<EventHandler<ProtocolStatusChangeEventArgs>>(ref ProtocolStatusChangeEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_CLIST_STATUSMODECHANGE, ProtocolStatusChangeEventHandler);
}
}
public event EventHandler<ContactListEventArgs<ContactInfo>> ContactMenuShowing
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<EventHandler<ContactListEventArgs<ContactInfo>>>(ref ContactMenuShowingEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_CLIST_PREBUILDCONTACTMENU,
delegate(UIntPtr wParam, IntPtr lParam)
{
if (ContactMenuShowingEventHandler != null)
ContactMenuShowingEventHandler(this, new ContactListEventArgs<ContactInfo>(ContactInfo.FromHandle(wParam)));
return (int)CallbackResult.Success;
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<EventHandler<ContactListEventArgs<ContactInfo>>>(ref ContactMenuShowingEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_CLIST_PREBUILDCONTACTMENU, ContactMenuShowingEventHandler);
}
}
public event MirandaEventHandler<ContactListEventArgs<ContactInfo>> ContactDoubleClicked
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<MirandaEventHandler<ContactListEventArgs<ContactInfo>>>(ref ContactDoubleClickedEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_CLIST_DOUBLECLICKED,
delegate(UIntPtr wParam, IntPtr lParam)
{
bool retValue = InvokeChainCancelable<ContactListEventArgs<ContactInfo>>(ContactDoubleClickedEventHandler, new ContactListEventArgs<ContactInfo>(ContactInfo.FromHandle(wParam)));
return Convert.ToInt32(retValue);
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<MirandaEventHandler<ContactListEventArgs<ContactInfo>>>(ref ContactDoubleClickedEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_CLIST_DOUBLECLICKED, ContactDoubleClickedEventHandler);
}
}
#endregion
#region Methods
#region Menu
public void AddMenuItem(MirandaPlugin owner, MenuItemDeclarationAttribute item)
{
if (owner == null)
throw new ArgumentNullException("owner");
if (item == null)
throw new ArgumentNullException("item");
string serviceName = item.IsContactMenuItem ? MirandaServices.MS_CLIST_ADDCONTACTMENUITEM : MirandaServices.MS_CLIST_ADDMAINMENUITEM;
UnmanagedStructHandle<CLISTMENUITEM> nativeHandle = UnmanagedStructHandle<CLISTMENUITEM>.Empty;
CLISTMENUITEM nativeItem = new CLISTMENUITEM(owner, item);
try
{
nativeHandle = new UnmanagedStructHandle<CLISTMENUITEM>(ref nativeItem);
IntPtr handle = (IntPtr)MirandaContext.Current.CallService(serviceName, UIntPtr.Zero, nativeHandle.IntPtr,
(owner is StandalonePlugin && !item.IsAdditional));
item.MirandaHandle = handle;
Debug.Assert(handle != IntPtr.Zero);
}
finally
{
nativeHandle.Free();
}
}
public bool ModifyMenuItem(MirandaPlugin owner, MenuItemDeclarationAttribute menuItem, string text)
{
return ModifyMenuItem(owner, menuItem, text, MenuItemProperties.None, null, 0, true);
}
public bool ModifyMenuItem(MirandaPlugin owner, MenuItemDeclarationAttribute menuItem, MenuItemProperties flags)
{
return ModifyMenuItem(owner, menuItem, null, flags, null, 0, true);
}
public bool ModifyMenuItem(MirandaPlugin owner, MenuItemDeclarationAttribute menuItem, HotKeys hotKey)
{
return ModifyMenuItem(owner, menuItem, null, MenuItemProperties.None, null, hotKey, true);
}
public bool ModifyMenuItem(MirandaPlugin owner, MenuItemDeclarationAttribute menuItem, Icon icon)
{
return ModifyMenuItem(owner, menuItem, null, MenuItemProperties.None, icon, 0, true);
}
public bool ModifyMenuItem(MirandaPlugin owner, MenuItemDeclarationAttribute menuItem, string text, MenuItemProperties flags, Icon icon, HotKeys hotKey)
{
return ModifyMenuItem(owner, menuItem, text, flags, icon, hotKey, true);
}
public bool ModifyMenuItem(MirandaPlugin owner, MenuItemDeclarationAttribute menuItem, string text, MenuItemProperties flags, Icon icon, HotKeys hotKey, bool updateItemDescriptor)
{
if (owner == null)
throw new ArgumentNullException("owner");
if (menuItem == null)
throw new ArgumentNullException("menuItem");
if (menuItem.MirandaHandle == IntPtr.Zero)
throw new ArgumentException("Invalid menu item handle.");
UnmanagedStructHandle<CLISTMENUITEM> nativeHandle = UnmanagedStructHandle<CLISTMENUITEM>.Empty;
try
{
SynchronizationHelper.BeginMenuItemUpdate(menuItem);
CLISTMENUITEM nativeItem = new CLISTMENUITEM(owner, menuItem);
MenuItemModifyFlags modifyFlags = MenuItemModifyFlags.None;
if (text != null)
{
modifyFlags |= MenuItemModifyFlags.CMIM_NAME;
nativeItem.Text = text;
if (updateItemDescriptor) menuItem.Text = text;
}
if (flags != MenuItemProperties.KeepCurrent)
{
modifyFlags |= MenuItemModifyFlags.CMIM_FLAGS;
nativeItem.Flags = (uint)flags;
if (updateItemDescriptor) menuItem.Flags = flags;
}
if (icon != null)
{
modifyFlags |= MenuItemModifyFlags.CMIM_ICON;
nativeItem.Icon = icon.Handle;
}
if (hotKey != 0)
{
modifyFlags |= MenuItemModifyFlags.CMIM_HOTKEY;
nativeItem.HotKey = (uint)hotKey;
if (updateItemDescriptor) menuItem.HotKey = hotKey;
}
nativeItem.Flags |= (uint)modifyFlags;
nativeHandle = new UnmanagedStructHandle<CLISTMENUITEM>(ref nativeItem);
bool result = MirandaContext.Current.CallService(MirandaServices.MS_CLIST_MODIFYMENUITEM, (UIntPtr)(uint)menuItem.MirandaHandle, nativeHandle.IntPtr) == 0
? true : false;
Debug.Assert(result);
return result;
}
catch (Exception e)
{
throw new MirandaException(TextResources.ExceptionMsg_ErrorWhileCallingMirandaService + e.Message, e);
}
finally
{
nativeHandle.Free();
SynchronizationHelper.EndUpdate(menuItem);
}
}
#endregion
#region UI
public bool ShowBaloonTip(string title, string text, string protocol, ToolTipIcon icon, int timeout)
{
UnmanagedStructHandle<MIRANDASYSTRAYNOTIFY> nativeHandle = UnmanagedStructHandle<MIRANDASYSTRAYNOTIFY>.Empty;
try
{
MIRANDASYSTRAYNOTIFY msn = new MIRANDASYSTRAYNOTIFY(title, text, icon);
msn.Timeout = (uint)timeout;
msn.Protocol = protocol;
nativeHandle = new UnmanagedStructHandle<MIRANDASYSTRAYNOTIFY>(ref msn);
int result = MirandaContext.Current.CallService(MirandaServices.MS_CLIST_SYSTRAY_NOTIFY, UIntPtr.Zero, nativeHandle.IntPtr);
bool retValue = (result == 0);
Debug.Assert(retValue);
return retValue;
}
finally
{
nativeHandle.Free();
}
}
public bool SetInfoTipHoverTime(int time)
{
int result = MirandaContext.Current.CallService(MS_CLC_SETINFOTIPHOVERTIME, (UIntPtr)(uint)time, IntPtr.Zero);
Debug.Assert(result == 0);
return result == 0;
}
public int GetInfoTipHoverTime()
{
return MirandaContext.Current.CallService(MS_CLC_GETINFOTIPHOVERTIME);
}
public void EnableContactSelectionTracking()
{
lock (SyncObject)
{
if (ContactSelectionTrackingEnabled)
return;
ContactMenuShowing += HandleContactSelection;
ContactSelectionTrackingEnabled = true;
MirandaContext.Current.IsolatedModePluginsUnloading += delegate { ContactMenuShowing -= HandleContactSelection; };
}
}
private void HandleContactSelection(object sender, ContactListEventArgs<ContactInfo> e)
{
lock (SyncObject)
selectedContact = e.EventData;
}
#endregion
#region Events
public IntPtr AddEvent(ContactInfo contact, Icon icon, string serviceToCall, ContactListEventProperties properties, string toolTip)
{
if (contact == null)
throw new ArgumentNullException("contact");
return AddEvent(contact, icon, serviceToCall, IntPtr.Zero, contact.MirandaHandle, properties, toolTip);
}
public IntPtr AddEvent(ContactInfo contact, Icon icon, string serviceToCall, IntPtr lParamToPass, IntPtr eventToken, ContactListEventProperties properties, string toolTip)
{
if (contact == null)
throw new ArgumentNullException("contact");
if (icon == null)
throw new ArgumentNullException("icon");
ContactListEvent clistEvent = new ContactListEvent();
clistEvent.ContactHandle = contact.MirandaHandle;
clistEvent.EventHandle = eventToken;
clistEvent.Flags = (uint)properties;
clistEvent.IconHandle = icon.Handle;
clistEvent.LParam = lParamToPass;
clistEvent.ServiceName = serviceToCall;
clistEvent.Tooltip = toolTip;
UnmanagedStructHandle<ContactListEvent> nativeStruct = UnmanagedStructHandle<ContactListEvent>.Empty;
try
{
nativeStruct = new UnmanagedStructHandle<ContactListEvent>(ref clistEvent);
IntPtr eventHandle = (IntPtr)MirandaContext.Current.CallService(MS_CLIST_ADDEVENT, UIntPtr.Zero, nativeStruct.IntPtr);
if (eventHandle != IntPtr.Zero)
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MS_CLIST_ADDEVENT, eventHandle.ToString()));
return clistEvent.EventHandle;
}
finally
{
nativeStruct.Free();
}
}
public bool RemoveEvent(ContactInfo contact)
{
if (contact == null)
throw new ArgumentNullException("contact");
return RemoveEvent(contact, contact.MirandaHandle);
}
public bool RemoveEvent(ContactInfo contact, IntPtr eventToken)
{
if (contact == null)
throw new ArgumentNullException("contact");
return !Convert.ToBoolean(MirandaContext.Current.CallService(MS_CLIST_REMOVEEVENT, contact.MirandaHandle, eventToken));
}
#endregion
#endregion
}
}
@@ -0,0 +1,91 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public sealed class ContactListEvent
{
#region Native fields
private readonly int Size;
internal IntPtr ContactHandle;
internal IntPtr IconHandle;
internal UInt32 Flags;
internal IntPtr EventHandle;
internal IntPtr lParam;
internal string ServiceName;
internal string Tooltip;
#endregion
#region .ctors
internal ContactListEvent()
{
Size = Marshal.SizeOf(this);
}
public static ContactListEvent FromPointer(IntPtr pClistEvent)
{
if (pClistEvent == IntPtr.Zero)
throw new ArgumentNullException("pClistEventHandle");
return (ContactListEvent)Marshal.PtrToStructure(pClistEvent, typeof(ContactListEvent));
}
#endregion
#region Managed properties
public ContactInfo Contact
{
get { return ContactInfo.FromHandle(ContactHandle); }
}
public IntPtr LParam
{
get { return lParam; }
internal set { lParam = value; }
}
#endregion
}
// typedef struct {
// int cbSize; //size in bytes of this structure
// HANDLE hContact; //handle to the contact to put the icon by
// HICON hIcon; //icon to flash
// DWORD flags; //...of course
// union
// {
// HANDLE hDbEvent; //caller defined but should be unique for hContact
// char * lpszProtocol;
// };
// LPARAM lParam; //caller defined
// char *pszService; //name of the service to call on activation
// union {
// char *pszTooltip; //short description of the event to display as a
// TCHAR *ptszTooltip; //tooltip on the system tray
// };
//} CLISTEVENT;
}
@@ -0,0 +1,49 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[Serializable]
public class ContactListEventArgs<T> : MirandaEventArgs
{
#region Fields
private T eventData;
public T EventData
{
get
{
return this.eventData;
}
}
#endregion
#region .ctors
internal ContactListEventArgs(T eventData)
{
this.eventData = eventData;
}
#endregion
}
}
@@ -0,0 +1,81 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct ContactListInfoTip
{
#region Native fields
private int size, isTreeFocused, isGroup;
private IntPtr itemPtr;
private Point point;
private Rectangle rectangle;
#endregion
#region Properties
public bool IsTreeFocused
{
get { return Convert.ToBoolean(isTreeFocused); }
}
public bool IsGroup
{
get { return Convert.ToBoolean(isGroup); }
}
public MirandaItem Item
{
get
{
return IsGroup ? (MirandaItem)new GroupInfo(itemPtr) : (MirandaItem)ContactInfo.FromHandle(itemPtr);
}
}
public Point Point
{
get { return point; }
}
public Rectangle Rectangle
{
get { return rectangle; }
}
#endregion
}
/*
* typedef struct {
int cbSize;
int isTreeFocused; //so the plugin can provide an option
int isGroup; //0 if it's a contact, 1 if it's a group
HANDLE hItem; //handle to group or contact
POINT ptCursor;
RECT rcItem;
} CLCINFOTIP;*/
}
@@ -0,0 +1,36 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
/// <summary>
/// Represents a base class for cross-domain callable object that operate with Miranda Context.
/// </summary>
public abstract class ContextWorker : RemoteObject
{
protected internal ContextWorker() { }
protected MirandaContext Context
{
get { return MirandaContext.Current; }
}
}
}
@@ -0,0 +1,419 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Virtuoso.Miranda.Plugins.Resources;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
/// <summary>
/// Represents database event information.
/// </summary>
public class DatabaseEventInfo : IMirandaObject
{
#region Constants
private const string MS_DB_EVENT_GETBLOBSIZE = "DB/Event/GetBlobSize";
/// <summary>
/// DB/Event/Get
/// Retrieves all the information stored in hDbEvent
/// wParam=(WPARAM)(HANDLE)hDbEvent
/// lParam=(LPARAM)(DBEVENTINFO*)&amp;dbe
/// hDbEvent should have been returned by db/event/add or db/event/find*event
/// Returns 0 on success or nonzero if hDbEvent is invalid
/// Don't forget to set dbe.cbSize, dbe.pBlob and dbe.cbBlob before calling this
/// service
/// The correct value dbe.cbBlob can be got using db/event/getblobsize
/// If successful, all the fields of dbe are filled. dbe.cbBlob is set to the
/// actual number of bytes retrieved and put in dbe.pBlob
/// If dbe.cbBlob is too small, dbe.pBlob is filled up to the size of dbe.cbBlob
/// and then dbe.cbBlob is set to the required size of data to go in dbe.pBlob
/// On return, dbe.szModule is a pointer to the database module's own internal list
/// of modules. Look but don't touch.
/// </summary>
private const string MS_DB_EVENT_GET = "DB/Event/Get";
private const string MS_DB_TIME_TIMESTAMPTOSTRING = "DB/Time/TimestampToString";
/// <summary>
/// DB/Event/GetContact
/// Retrieves a handle to the contact that owns hDbEvent.
/// wParam=(WPARAM)(HANDLE)hDbEvent
/// lParam=0
/// hDbEvent should have been returned by db/event/add or db/event/find*event
/// NULL is a valid return value, meaning, as usual, the user.
/// Returns (HANDLE)(-1) if hDbEvent is invalid, or the handle to the contact on
/// success
/// This service is exceptionally slow. Use only when you have no other choice at
/// all.
/// </summary>
private const string MS_DB_EVENT_GETCONTACT = "DB/Event/GetContact";
/// <summary>
/// DB/Event/GetText (0.7.0+)
/// Retrieves the event's text
/// wParam=(WPARAM)0 (unused)
/// lParam=(LPARAM)(DBEVENTGETTEXT*)egt - pointer to structure with parameters
/// egt->dbei should be the valid database event read via MS_DB_EVENT_GET
/// egt->datatype = DBVT_WCHAR or DBVT_ASCIIZ or DBVT_TCHAR. If a caller wants to
/// suppress Unicode part of event in answer, add DBVTF_DENYUNICODE to this field.
/// egt->codepage is any valid codepage, CP_ACP by default.
/// Function returns a pointer to a string in the required format.
/// This string should be freed by a call of mir_free
/// </summary>
private const string MS_DB_EVENT_GETTEXT = "DB/Event/GetText";
#endregion
#region .ctors
/// <summary>
/// Initializes a new instance of the <see cref="DatabaseEventInfo"/> class.
/// </summary>
protected DatabaseEventInfo() { }
/// <summary>
/// Initializes a new instance of the <see cref="DatabaseEventInfo"/> class.
/// </summary>
/// <param name="mirandaHandle">Event handle.</param>
protected DatabaseEventInfo(IntPtr eventHandle)
{
if (eventHandle == IntPtr.Zero)
throw new ArgumentNullException("eventHandle");
this.mirandaHandle = eventHandle;
FromHandle(eventHandle, out type, out flags, out data, out owningModule, out timestamp);
}
/// <summary>
/// Creates a new instance of the <see cref="DatabaseEventInfo"/> from an event handle.
/// </summary>
/// <param name="mirandaHandle">Event handle.</param>
/// <returns>Database event info.</returns>
public static DatabaseEventInfo FromHandle(IntPtr eventHandle)
{
return new DatabaseEventInfo(eventHandle);
}
#endregion
#region Initializers
/// <summary>
/// Gets the event information based on its handle.
/// </summary>
/// <param name="eventHandle">Event handle.</param>
/// <param name="type">[OUT] Event type.</param>
/// <param name="flags">[OUT] Event flags.</param>
/// <param name="data">[OUT] Event data.</param>
/// <param name="owningModule">[OUT] Event related module.</param>
/// <param name="timestamp">[OUT] Event timestamp.</param>
public static void FromHandle(IntPtr eventHandle, out DatabaseEventType type, out DatabaseEventProperties flags, out string data, out Protocol owningModule, out DateTime timestamp)
{
InteropBuffer buffer = null;
try
{
unsafe
{
DBEVENTINFO dbEventInfo;
PrepareDbEventInfo(eventHandle, out dbEventInfo, out buffer);
GetEventInfo(ref dbEventInfo, eventHandle, buffer, out type, out flags, out data, out owningModule, out timestamp);
}
}
catch (MirandaException)
{
throw;
}
catch (Exception e)
{
throw new InvalidOperationException(TextResources.ExceptionMsg_CannotFinishMarshaling, e);
}
finally
{
if (buffer != null)
{
buffer.Unlock();
InteropBufferPool.ReleaseBuffer(buffer);
}
}
}
/// <summary>
/// Prepares the <see cref="DBEVENTINFO"/> for information extraction and the blob buffer.
/// </summary>
/// <param name="eventHandle">Event handle.</param>
/// <param name="dbEventInfo">[OUT] DB event info to marshal data into.</param>
/// <param name="buffer">[OUT] Locked Blob buffer.</param>
private unsafe static void PrepareDbEventInfo(IntPtr eventHandle, out DBEVENTINFO dbEventInfo, out InteropBuffer buffer)
{
int blobSize = MirandaContext.Current.CallServiceUnsafe(MS_DB_EVENT_GETBLOBSIZE, eventHandle.ToPointer(), null);
if (blobSize == -1)
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MS_DB_EVENT_GETBLOBSIZE, blobSize.ToString()));
// Acquire a buffer for the blob
buffer = InteropBufferPool.AcquireBuffer(blobSize);
buffer.Lock();
dbEventInfo = new DBEVENTINFO(blobSize, buffer.IntPtr);
}
/// <summary>
/// Initializes the instance by marshaling data from a <see cref="DBEVENTINFO"/> pointer.
/// </summary>
/// <param name="pDbEventInfo"><see cref="DBEVENTINFO"/> pointer.</param>
private void MarshalEventInfo(IntPtr pDbEventInfo)
{
DBEVENTINFO info = (DBEVENTINFO)Marshal.PtrToStructure(pDbEventInfo, typeof(DBEVENTINFO));
// Get an appropriately size buffer for the blob
InteropBuffer buffer = InteropBufferPool.AcquireBuffer((int)info.BlobSize);
try
{
buffer.Lock();
GetEventInfo(ref info, IntPtr.Zero, buffer, out type, out flags, out data, out owningModule, out timestamp);
}
finally
{
buffer.Unlock();
InteropBufferPool.ReleaseBuffer(buffer);
}
}
/// <summary>
/// Get the event information from a <see cref="DBEVENTINFO"/> struct.
/// </summary>
/// <param name="dbEventInfo">[REF] <see cref="DBEVENTINFO"/> struct.</param>
/// <param name="mirandaHandle">Event handle (the blob buffer will be populated if not null).</param>
/// <param name="blobBuffer">Buffer to use for blob marshaling.</param>
/// <param name="type">[OUT] Event type.</param>
/// <param name="flags">[OUT] Event flags.</param>
/// <param name="data">[OUT] Event data.</param>
/// <param name="owningModule">[OUT] Event related module.</param>
/// <param name="timestamp">[OUT] Event timestamp.</param>
private static void GetEventInfo(ref DBEVENTINFO dbEventInfo, IntPtr eventHandle, InteropBuffer blobBuffer, out DatabaseEventType type, out DatabaseEventProperties flags, out string data, out Protocol owningModule, out DateTime timestamp)
{
MirandaContext context = MirandaContext.Current;
unsafe
{
// If the event handle is set, we probably want to populate the blob buffer...
if (eventHandle != IntPtr.Zero)
PopulateBlobBuffer(ref dbEventInfo, eventHandle);
type = (DatabaseEventType)dbEventInfo.EventType;
flags = (DatabaseEventProperties)dbEventInfo.Flags;
data = GetEventData(ref dbEventInfo);
}
owningModule = GetEventModule(ref dbEventInfo);
GetEventTimestamp(ref dbEventInfo, blobBuffer, out timestamp);
}
/// <summary>
/// Populates the blob buffer set by the <see cref="DBEVENTINFO"/> parameter.
/// </summary>
/// <param name="dbEventInfo">[REF] <see cref="DBEVENTINFO"/> struct identifiing the buffer.</param>
/// <param name="eventHandle">Event handle.</param>
/// <exception cref="MirandaException">Buffer could bet populated.</exception>
private unsafe static void PopulateBlobBuffer(ref DBEVENTINFO dbEventInfo, IntPtr eventHandle)
{
int result;
fixed (void* pDbEventInfo = &dbEventInfo)
result = MirandaContext.Current.CallServiceUnsafe(MS_DB_EVENT_GET, eventHandle.ToPointer(), pDbEventInfo);
if (result != 0)
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MS_DB_EVENT_GET, result.ToString()));
}
/// <summary>
/// Gets the event timestamp.
/// </summary>
/// <param name="dbEventInfo">[REF] <see cref="DBEVENTINFO"/> struct.</param>
/// <param name="blobBuffer">Buffer to reuse.</param>
/// <param name="timestamp">[OUT] Timestamp.</param>
private static void GetEventTimestamp(ref DBEVENTINFO dbEventInfo, InteropBuffer blobBuffer, out DateTime timestamp)
{
try
{
DBTIMETOSTRING timeToString = new DBTIMETOSTRING("s D");
timeToString.MaxBytes = blobBuffer.Size;
timeToString.Output = blobBuffer.IntPtr;
unsafe
{
MirandaContext.Current.CallServiceUnsafe(MS_DB_TIME_TIMESTAMPTOSTRING, (void*)dbEventInfo.Timestamp, &timeToString);
}
timestamp = DateTime.Parse(Translate.ToString(timeToString.Output, StringEncoding.Ansi));
}
catch (FormatException)
{
timestamp = DateTime.MinValue;
}
}
/// <summary>
/// Gets the event module.
/// </summary>
/// <param name="dbEventInfo">[REF] <see cref=">DBEVENTINFO"/> struct.</param>
/// <returns>Event module.</returns>
private static Protocol GetEventModule(ref DBEVENTINFO dbEventInfo)
{
Protocol owningModule;
bool moduleFound = false;
if (dbEventInfo.Module != IntPtr.Zero)
moduleFound = MirandaContext.Current.Protocols.TryGetValue(Translate.ToString(dbEventInfo.Module, StringEncoding.Ansi), out owningModule);
else
owningModule = Protocol.UnknownProtocol;
if (!moduleFound)
owningModule = Protocol.UnknownProtocol;
return owningModule;
}
/// <summary>
/// Gets the event data.
/// </summary>
/// <param name="dbEventInfo">[REF] <see cref="DBEVENTINFO"/> struct.</param>
/// <returns>Event data.</returns>
private unsafe static string GetEventData(ref DBEVENTINFO dbEventInfo)
{
string data;
DBEVENTGETTEXT dbGetText = new DBEVENTGETTEXT();
dbGetText.Codepage = 0;
dbGetText.DataType = (int)DatabaseSettingType.UnicodeString;
IntPtr pText;
fixed (void* pDbEventInfo = &dbEventInfo)
{
dbGetText.DbEventInfoPtr = new IntPtr(pDbEventInfo);
pText = (IntPtr)MirandaContext.Current.CallServiceUnsafe(MS_DB_EVENT_GETTEXT, null, &dbGetText);
}
if (pText != IntPtr.Zero)
{
data = Translate.ToString(pText, StringEncoding.Unicode);
MirandaContext.Current.MirandaMemoryManager.Free(pText);
}
else
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MS_DB_EVENT_GETTEXT, "null"));
return data;
}
#endregion
#region Properties
private IntPtr mirandaHandle;
public IntPtr MirandaHandle
{
get { return mirandaHandle; }
}
private Protocol owningModule;
public Protocol OwningModule
{
get { return owningModule; }
}
private DateTime timestamp;
public DateTime Timestamp
{
get { return timestamp; }
}
private DatabaseEventProperties flags;
public DatabaseEventProperties Flags
{
get { return flags; }
}
private DatabaseEventType type;
public DatabaseEventType Type
{
get { return type; }
}
private string data;
public string Data
{
get { return data; }
}
#endregion
#region Methods
/// <summary>
/// Marshals the <see cref="DatabaseEventInfo"/> from a <see cref="DBEVENTINFO"/> struct pointer.
/// </summary>
/// <param name="pDbEventInfo"><see cref="DBEVENTINFO"/> struct pointer.</param>
/// <returns>Event info.</returns>
internal static DatabaseEventInfo FromPointer(IntPtr pDbEventInfo)
{
DatabaseEventInfo info = new DatabaseEventInfo();
info.MarshalEventInfo(pDbEventInfo);
return info;
}
/// <summary>
/// Gets the handle of the contact owning this event. This method is very slow, use wisely.
/// </summary>
/// <returns>Associated contact handle.</returns>
public IntPtr GetContactHandle()
{
return GetContactHandle(mirandaHandle);
}
/// <summary>
/// Gets the handle of the contact owning this event. This method is very slow, use wisely.
/// </summary>
/// <param name="eventHandle">Event handle to get the contact handle for.</param>
/// <returns>Associated contact handle.</returns>
public static IntPtr GetContactHandle(IntPtr eventHandle)
{
if (eventHandle == IntPtr.Zero)
throw new ArgumentNullException("eventHandle");
int contactHandle = MirandaContext.Current.CallService(MS_DB_EVENT_GETCONTACT, eventHandle, IntPtr.Zero);
if (contactHandle == -1)
throw new ArgumentException(TextResources.ExceptionMsg_InvalidHandle, "eventHandle");
return (IntPtr)contactHandle;
}
#endregion
}
}
@@ -0,0 +1,114 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using Virtuoso.Miranda.Plugins.Resources;
using Virtuoso.Hyphen;
using System.Runtime.CompilerServices;
using Virtuoso.Miranda.Plugins.Collections;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[CLSCompliant(false)]
public sealed class EventHandle : MirandaObject
{
#region Fields
private readonly MirandaPlugin owner;
internal MirandaPlugin Owner
{
get { return owner; }
}
private readonly string eventName;
public string EventName
{
get { return eventName; }
}
#endregion
#region .ctors
internal EventHandle(MirandaPlugin owner, string eventName, IntPtr handle)
{
if (handle == IntPtr.Zero)
throw new ArgumentNullException("handle");
if (owner == null)
throw new ArgumentNullException("owner");
if (eventName == null)
throw new ArgumentNullException("eventName");
this.owner = owner;
this.MirandaHandle = handle;
this.eventName = eventName;
List<EventHandle> eventHandles = owner.Descriptor.EventHandles;
try
{
SynchronizationHelper.BeginCollectionUpdate(eventHandles);
eventHandles.Add(this);
}
finally
{
SynchronizationHelper.EndUpdate(eventHandles);
}
}
#endregion
#region Methods
public int FireEvent()
{
return FireEvent(UIntPtr.Zero, IntPtr.Zero);
}
public int FireEvent(UIntPtr wParam, IntPtr lParam)
{
MirandaPluginLink link = MirandaContext.Current.PluginLink;
lock (link)
return link.NativePluginLink.NotifyEventHooks(MirandaHandle, wParam, lParam);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetDefaultSubscriber(Callback subscriber)
{
if (subscriber == null)
throw new ArgumentNullException("subscriber");
MirandaPluginLink link = MirandaContext.Current.PluginLink;
lock (link)
{
int result;
if ((result = link.NativePluginLink.SetHookDefaultForHookableEvent(MirandaHandle, subscriber)) != 0)
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, "SetHookDefaultForHookableEvent", result.ToString()));
}
}
#endregion
}
}
@@ -0,0 +1,66 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public sealed class EventHookAttribute : HookAttribute
{
#region Fields
private string eventName;
public string EventName
{
get
{
return this.eventName;
}
set
{
this.eventName = value;
}
}
internal override string HookName
{
get { return EventName; }
}
internal override HookType HookType
{
get { return HookType.EventHook; }
}
#endregion
#region .ctors
public EventHookAttribute(string eventName)
{
if (eventName == null)
throw new ArgumentNullException("eventName");
this.eventName = eventName;
}
#endregion
}
}
@@ -0,0 +1,151 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Collections;
using Virtuoso.Miranda.Plugins.Resources;
using Virtuoso.Hyphen;
using Virtuoso.Miranda.Plugins.Native;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public static class EventManager
{
[CLSCompliant(false)]
public static void CreateEventHook(string eventName, Callback callback, MirandaPlugin owner)
{
if (String.IsNullOrEmpty(eventName))
throw new ArgumentNullException("eventName");
if (callback == null)
throw new ArgumentNullException("callback");
if (owner == null)
throw new ArgumentNullException("owner");
if (!owner.Initialized)
throw new InvalidOperationException(TextResources.ExceptionMsg_PluginNotInitialized);
HookDescriptorCollection collection = owner.Descriptor.EventHooks;
try
{
SynchronizationHelper.BeginPluginUpdate(owner);
SynchronizationHelper.BeginCollectionUpdate(collection);
HookDescriptor descriptor = HookDescriptor.SetUpAndStore(collection, eventName, owner.Descriptor, callback, HookType.EventHook);
descriptor.RegisteredManually = true;
HookManager.CreateHook(descriptor);
}
finally
{
SynchronizationHelper.EndUpdate(owner);
SynchronizationHelper.EndUpdate(collection);
}
}
public static void RemoveEventHook(string eventName, MirandaPlugin owner)
{
if (String.IsNullOrEmpty(eventName))
throw new ArgumentNullException("eventName");
if (owner == null)
throw new ArgumentNullException("owner");
if (!owner.Initialized)
throw new InvalidOperationException(TextResources.ExceptionMsg_PluginNotInitialized);
HookDescriptorCollection collection = owner.Descriptor.EventHooks;
try
{
SynchronizationHelper.BeginCollectionUpdate(collection);
HookDescriptor descriptor = null;
if ((descriptor = owner.Descriptor.EventHooks.Find(eventName)) == null)
return;
HookManager.DestroyHook(descriptor);
collection.Remove(descriptor);
}
finally
{
SynchronizationHelper.EndUpdate(collection);
}
}
[CLSCompliant(false)]
public static EventHandle CreateEvent(string eventName, MirandaPlugin owner)
{
return CreateEvent(eventName, owner, null);
}
[CLSCompliant(false)]
public static EventHandle CreateEvent(string eventName, MirandaPlugin owner, Callback defaultSubscriber)
{
if (String.IsNullOrEmpty(eventName))
throw new ArgumentNullException("eventName");
if (owner == null)
throw new ArgumentNullException("owner");
if (!owner.Initialized)
throw new InvalidOperationException(TextResources.ExceptionMsg_PluginNotInitialized);
if (ServiceManager.ServiceExists(eventName))
throw new ArgumentException("eventName");
EventHandle handle = new EventHandle(owner, eventName, MirandaContext.Current.PluginLink.NativePluginLink.CreateHookableEvent(eventName));
if (defaultSubscriber != null)
handle.SetDefaultSubscriber(defaultSubscriber);
return handle;
}
public static void RemoveEvent(EventHandle eventHandle)
{
if (eventHandle == null)
throw new ArgumentNullException("eventHandle");
MirandaPluginLink link = MirandaContext.Current.PluginLink;
if (eventHandle.MirandaHandle != IntPtr.Zero)
{
int result;
if ((result = link.NativePluginLink.DestroyHookableEvent(eventHandle.MirandaHandle)) != 0)
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, "DestroyHookableEvent", result.ToString()));
eventHandle.MirandaHandle = IntPtr.Zero;
EventHandleCollection handles = eventHandle.Owner.Descriptor.EventHandles;
try
{
SynchronizationHelper.BeginCollectionUpdate(handles);
handles.Remove(eventHandle);
}
finally
{
SynchronizationHelper.EndUpdate(handles);
}
}
}
}
}
@@ -0,0 +1,49 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public abstract class EventPublisher
{
internal EventPublisher() { }
protected bool InvokeChainCancelable<TEventArgs>(MirandaEventHandler<TEventArgs> handler, TEventArgs eventArgs) where TEventArgs : MirandaEventArgs
{
return InvokeChainCancelable<TEventArgs>(handler, this, eventArgs);
}
public static bool InvokeChainCancelable<TEventArgs>(MirandaEventHandler<TEventArgs> handler, object sender, TEventArgs eventArgs) where TEventArgs : MirandaEventArgs
{
bool retValue = EventResult.HonourEventChain;
if (handler != null)
{
foreach (MirandaEventHandler<TEventArgs> del in handler.GetInvocationList())
{
if ((retValue = del(sender, eventArgs)) == EventResult.BreakEventChain)
break;
}
}
return retValue;
}
}
}
@@ -0,0 +1,75 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public sealed class GroupInfo : MirandaItem
{
#region Fields
private const string MS_CLIST_GROUPGETNAME = "CList/GroupGetName";
#endregion
#region .ctors
internal GroupInfo(IntPtr handle) : base(handle, ItemType.Group) { }
#endregion
#region Properties
public string Name
{
get
{
IntPtr pName = (IntPtr)MirandaContext.Current.CallService(MS_CLIST_GROUPGETNAME, MirandaHandle, IntPtr.Zero);
Debug.Assert(pName != IntPtr.Zero);
if (pName != IntPtr.Zero)
return Marshal.PtrToStringAnsi(pName);
else
return null;
}
}
public unsafe bool IsExpanded
{
get
{
int expanded = 0;
IntPtr pName = (IntPtr)MirandaContext.Current.CallServiceUnsafe(MS_CLIST_GROUPGETNAME, MirandaHandle.ToPointer(), &expanded);
Debug.Assert(pName != IntPtr.Zero);
if (pName != IntPtr.Zero)
return Convert.ToBoolean(expanded);
else
return false;
}
}
#endregion
}
}
@@ -0,0 +1,32 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public abstract class HookAttribute : Attribute
{
protected internal HookAttribute() { }
internal abstract string HookName { get; }
internal abstract HookType HookType { get; }
}
}
@@ -0,0 +1,164 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Virtuoso.Hyphen;
using Virtuoso.Miranda.Plugins.Forms;
using Virtuoso.Hyphen.Mini;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
internal sealed class HookDescriptor : IMirandaObject, IDescriptor
{
#region Fields
private string name;
private IntPtr handle;
private Callback callback, callbackStub;
private HookType hookType;
private PluginDescriptor owner;
private bool registeredManually;
#endregion
#region .ctor
public HookDescriptor(string name, PluginDescriptor owner, Callback callback, HookType type)
{
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
if (owner == null)
throw new ArgumentNullException("owner");
if (callback == null)
throw new ArgumentNullException("callback");
this.callbackStub = SafeCallbackStub;
this.name = name;
this.owner = owner;
this.callback = callback;
this.hookType = type;
}
public static HookDescriptor SetUpAndStore(IList<HookDescriptor> targetContainer, string name, PluginDescriptor owner, Callback callback, HookType type)
{
if (targetContainer == null)
throw new ArgumentNullException("targetContainer");
HookDescriptor descriptor = new HookDescriptor(name, owner, callback, type);
targetContainer.Add(descriptor);
return descriptor;
}
public static HookDescriptor SetUpAndStore(IDictionary<string, HookDescriptor> targetContainer, string name, PluginDescriptor owner, Callback callback, HookType type)
{
return SetUpAndStore<string>(targetContainer, name, name, owner, callback, type);
}
public static HookDescriptor SetUpAndStore<T>(IDictionary<T, HookDescriptor> targetContainer, T key, string name, PluginDescriptor owner, Callback callback, HookType type)
{
if (targetContainer == null)
throw new ArgumentNullException("targetContainer");
HookDescriptor descriptor = new HookDescriptor(name, owner, callback, type);
targetContainer.Add(key, descriptor);
return descriptor;
}
#endregion
#region Methods
private int SafeCallbackStub(UIntPtr wParam, IntPtr lParam)
{
try
{
return callback(wParam, lParam);
}
catch (Exception e)
{
MirandaPlugin.GetExceptionHandler(owner).HandleException(e, owner);
return (int)CallbackResult.Failure;
}
}
public override int GetHashCode()
{
return (name.GetHashCode() + callback.Method.Name.GetHashCode() + (int)hookType);
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
HookDescriptor other = obj as HookDescriptor;
if (other == null)
return false;
return GetHashCode() == other.GetHashCode();
}
#endregion
#region Properties
public string Name
{
get { return name; }
}
public IntPtr MirandaHandle
{
get { return handle; }
internal set { handle = value; }
}
public Callback Callback
{
get { return callbackStub; }
}
public HookType HookType
{
get { return hookType; }
}
public PluginDescriptor Owner
{
get { return owner; }
}
public bool RegisteredManually
{
get { return registeredManually; }
set { registeredManually = value; }
}
#endregion
}
}
@@ -0,0 +1,177 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Hyphen;
using Virtuoso.Miranda.Plugins.Native;
using Virtuoso.Miranda.Plugins.Resources;
using System.Diagnostics;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
internal static class HookManager
{
public static void CreateHooks(params HookDescriptor[] hooks)
{
if (hooks == null)
throw new ArgumentNullException("hooks");
if (hooks.Length == 0)
return;
foreach (HookDescriptor hook in hooks)
CreateHook(hook);
}
public static void CreateHook(HookDescriptor hook)
{
try
{
SynchronizationHelper.BeginDescriptorUpdate(hook);
switch (hook.HookType)
{
case HookType.EventHook:
{
HookEvent(hook);
break;
}
case HookType.ServiceFunction:
{
CreateServiceFunction(hook);
break;
}
default:
throw new ArgumentException("descriptor");
}
}
finally
{
SynchronizationHelper.EndUpdate(hook);
}
}
private static void CreateServiceFunction(HookDescriptor hook)
{
if (!ServiceManager.ServiceExists(hook.Name))
{
hook.MirandaHandle = MirandaContext.Current.PluginLink.NativePluginLink.CreateServiceFunction(hook.Name, hook.Callback);
if (hook.MirandaHandle == IntPtr.Zero)
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable1_ServiceFunctionCreationFailed, hook.Name));
}
else
{
if (!hook.Owner.ServiceFunctions.Exists(delegate(HookDescriptor _hook)
{
return _hook.Equals(hook) && _hook.MirandaHandle != IntPtr.Zero;
}))
throw new InvalidOperationException(String.Format(TextResources.ExceptionMsg_Formatable1_ServiceFunctionAlreadyExists, hook.Name));
}
}
private static void HookEvent(HookDescriptor hook)
{
hook.MirandaHandle = MirandaContext.Current.PluginLink.NativePluginLink.HookEvent(hook.Name, hook.Callback);
if (hook.MirandaHandle == IntPtr.Zero)
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable1_EventHookingFailed, hook.Name));
}
public static void DestroyHook(HookDescriptor hook)
{
try
{
SynchronizationHelper.BeginDescriptorUpdate(hook);
switch (hook.HookType)
{
case HookType.EventHook:
{
UnhookEvent(hook);
break;
}
case HookType.ServiceFunction:
{
DestroyServiceFunction(hook);
break;
}
default:
throw new ArgumentException("descriptor");
}
}
finally
{
SynchronizationHelper.EndUpdate(hook);
}
}
private static void UnhookEvent(HookDescriptor descriptor)
{
if (descriptor == null)
throw new ArgumentNullException("descriptor");
if (descriptor.HookType != HookType.EventHook)
throw new ArgumentOutOfRangeException("descriptor");
if (descriptor.MirandaHandle == IntPtr.Zero)
return;
try
{
SynchronizationHelper.BeginDescriptorUpdate(descriptor);
int result = MirandaContext.Current.PluginLink.NativePluginLink.UnhookEvent(descriptor.MirandaHandle);
Debug.Assert(result == 0);
descriptor.MirandaHandle = IntPtr.Zero;
}
finally
{
SynchronizationHelper.EndUpdate(descriptor);
}
}
private static void DestroyServiceFunction(HookDescriptor descriptor)
{
if (descriptor == null)
throw new ArgumentNullException("descriptor");
if (descriptor.HookType != HookType.ServiceFunction)
throw new ArgumentOutOfRangeException("descriptor");
if (descriptor.MirandaHandle == IntPtr.Zero)
return;
try
{
SynchronizationHelper.BeginDescriptorUpdate(descriptor);
int result = MirandaContext.Current.PluginLink.NativePluginLink.DestroyServiceFunction(descriptor.MirandaHandle);
Debug.Assert(result == 0);
descriptor.MirandaHandle = IntPtr.Zero;
}
finally
{
SynchronizationHelper.EndUpdate(descriptor);
}
}
}
}
+30
View File
@@ -0,0 +1,30 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
internal enum HookType
{
Undefined,
EventHook,
ServiceFunction,
}
}
@@ -0,0 +1,28 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public interface IMirandaObject
{
IntPtr MirandaHandle { get; }
}
}
@@ -0,0 +1,28 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public interface ISettingOwner
{
string Name { get; }
}
}
@@ -0,0 +1,28 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public interface IStringResolver
{
string ResolveString(string stringToResolve, string tag);
}
}
@@ -0,0 +1,75 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using Virtuoso.Miranda.Plugins.Resources;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public static class LanguagePack
{
#region Enums
private enum LanguagePackEncoding : ushort
{
Ansi = 0,
Unicode = 0x1000
}
#endregion
#region Constants
private const string MS_LANGPACK_TRANSLATESTRING = "LangPack/TranslateString";
#endregion
#region FromPointer methods
public static string TranslateString(string str)
{
if (String.IsNullOrEmpty(str))
return str;
UnmanagedStringHandle stringHandle = UnmanagedStringHandle.Empty;
try
{
StringEncoding mirandaEncoding = MirandaEnvironment.MirandaStringEncoding;
LanguagePackEncoding encoding = (mirandaEncoding == StringEncoding.Unicode ? LanguagePackEncoding.Unicode : LanguagePackEncoding.Ansi);
stringHandle = new UnmanagedStringHandle(str, mirandaEncoding);
IntPtr translatedPtr = (IntPtr)MirandaContext.Current.CallService(MS_LANGPACK_TRANSLATESTRING, (UIntPtr)encoding, stringHandle.IntPtr);
return translatedPtr == stringHandle.IntPtr ? str : Translate.ToString(translatedPtr, mirandaEncoding);
}
catch (Exception e)
{
throw new MirandaException(TextResources.ExceptionMsg_ErrorWhileCallingMirandaService, e);
}
finally
{
stringHandle.Free();
}
}
#endregion
}
}
@@ -0,0 +1,33 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public class LanguagePackStringResolver : IStringResolver
{
public LanguagePackStringResolver() { }
public string ResolveString(string stringToResolve, string tag)
{
return LanguagePack.TranslateString(stringToResolve);
}
}
}
@@ -0,0 +1,102 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Virtuoso.Miranda.Plugins.Native;
using System.Threading;
using Virtuoso.Miranda.Plugins.Resources;
using System.Runtime.CompilerServices;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
/// <summary>
/// Represents a late-binded master subscriber of Miranda events.
/// </summary>
internal static class LazyEventBinder
{
#region Fields
private static readonly Dictionary<string, HookDescriptor> EventHandlerDescriptorsTable;
#endregion
#region .ctors
static LazyEventBinder()
{
EventHandlerDescriptorsTable = new Dictionary<string, HookDescriptor>(3);
}
#endregion
#region Management methods
public static void AttachDelegate<T>(ref T destination, T value) where T : class
{
if (value == null)
throw new ArgumentNullException("value");
if (!typeof(T).IsSubclassOf(typeof(Delegate)))
throw new ArgumentException("T");
destination = Delegate.Combine(destination as Delegate, value as Delegate) as T;
}
public static void DetachDelegate<T>(ref T destination, T value) where T : class
{
if (!typeof(T).IsSubclassOf(typeof(Delegate)))
throw new ArgumentException("T");
destination = Delegate.Remove(destination as Delegate, value as Delegate) as T;
}
public static void HookMirandaEvent(string eventName, Callback callback)
{
lock (EventHandlerDescriptorsTable)
{
if (EventHandlerDescriptorsTable.ContainsKey(eventName))
return;
HookDescriptor descriptor = HookDescriptor.SetUpAndStore(EventHandlerDescriptorsTable, eventName, MirandaPlugin.Hyphen.Singleton.Descriptor, callback, HookType.EventHook);
HookManager.CreateHook(descriptor);
}
}
public static void UnhookMirandaEvent(string eventName, Delegate callback)
{
if (callback != null)
return;
lock (EventHandlerDescriptorsTable)
{
if (!EventHandlerDescriptorsTable.ContainsKey(eventName))
return;
int result = MirandaContext.Current.PluginLink.NativePluginLink.UnhookEvent(EventHandlerDescriptorsTable[eventName].MirandaHandle);
Debug.Assert(result == 0);
EventHandlerDescriptorsTable.Remove(eventName);
}
}
#endregion
}
}
@@ -0,0 +1,214 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using System.Reflection;
using System.Diagnostics;
using Virtuoso.Miranda.Plugins.Resources;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public sealed class MenuItemDeclarationAttribute : Attribute, IMirandaObject
{
#region Fields & Properties
private static readonly Type StringResolverType = typeof(IStringResolver);
private string text;
public string Text
{
get { return text; }
set { text = value; }
}
private MenuItemProperties flags;
public MenuItemProperties Flags
{
get { return flags; }
set { flags = value; }
}
private int position, popUpPosition;
public int PopUpPosition
{
get { return popUpPosition; }
set { popUpPosition = value; }
}
public int Position
{
get { return position; }
set { position = value; }
}
private bool useEmbeddedIcon;
public bool UseEmbeddedIcon
{
get { return useEmbeddedIcon; }
set { useEmbeddedIcon = value; }
}
private bool hasIcon;
public bool HasIcon
{
get { return hasIcon; }
set { hasIcon = value; }
}
private string iconID;
public string IconID
{
get { return iconID; }
set { iconID = value; }
}
private string service;
public string Service
{
get { return service; }
internal set { service = value; }
}
private string popUpMenu;
public string PopUpMenu
{
get { return popUpMenu; }
}
private string owningModule;
public string OwningModule
{
get { return owningModule; }
set { owningModule = value; }
}
private HotKeys hotKey;
public HotKeys HotKey
{
get { return hotKey; }
set { hotKey = value; }
}
private Type stringResolver;
public Type StringResolver
{
get { return stringResolver; }
}
private string tag;
public string Tag
{
get { return tag; }
set { tag = value; }
}
private bool isContactMenuItem;
public bool IsContactMenuItem
{
get { return isContactMenuItem; }
set { isContactMenuItem = value; }
}
private IntPtr mirandaHandle;
public IntPtr MirandaHandle
{
get
{
return this.mirandaHandle;
}
internal set
{
this.mirandaHandle = value;
}
}
private bool isAdditional;
public bool IsAdditional
{
get { return isAdditional; }
set { isAdditional = value; }
}
#endregion
#region .ctors
public MenuItemDeclarationAttribute(string text) : this(text, null, null, null) { }
public MenuItemDeclarationAttribute(string text, Type stringResolver) : this(text, null, stringResolver) { }
public MenuItemDeclarationAttribute(string text, string service) : this(text, null, service, null) { }
public MenuItemDeclarationAttribute(string text, string popUpMenu, string service) : this(text, popUpMenu, service, null) { }
public MenuItemDeclarationAttribute(string text, string service, Type stringResolver) : this(text, null, service, stringResolver) { }
public MenuItemDeclarationAttribute(string text, string popUpMenu, string service, Type stringResolver)
{
if (text == null)
throw new ArgumentNullException("text");
this.text = text;
this.service = (service == null ? String.Empty : service);
this.popUpMenu = popUpMenu;
this.stringResolver = stringResolver;
/* m_clist.h
* WARNING: do not use Translate(TS) for p(t)szName or p(t)szPopupName as they
are translated by the core, which may lead to double translation. */
if (stringResolver != null && stringResolver.GetType() != typeof(LanguagePackStringResolver))
ResolveStrings(text, popUpMenu, stringResolver);
}
private void ResolveStrings(string text, string popUpMenu, Type stringResolver)
{
try
{
if (stringResolver != null && stringResolver.GetInterface(StringResolverType.FullName) != null)
{
IStringResolver resolver = null;
StringResolverCache cache = StringResolverCache.Singleton;
lock (cache)
{
if (!cache.TryGetValue(stringResolver, out resolver))
{
resolver = (IStringResolver)Activator.CreateInstance(stringResolver, true);
if (resolver == null)
throw new TypeLoadException(stringResolver.FullName);
else
cache.Add(stringResolver, resolver);
}
}
this.text = resolver.ResolveString(text, tag);
this.popUpMenu = resolver.ResolveString(popUpMenu, tag);
}
}
catch (Exception e)
{
throw new FusionException(String.Format(TextResources.ExceptionMsg_Formatable1_CannotLoadStringResolver, stringResolver.FullName), null, null, null, e);
}
}
#endregion
}
}
@@ -0,0 +1,54 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[Serializable]
public class MirandaContactEventArgs : MirandaEventArgs
{
#region Fields
private readonly ContactInfo contactInfo;
#endregion
#region .ctors
public MirandaContactEventArgs(ContactInfo contactInfo)
{
if (contactInfo == null)
throw new ArgumentNullException("contactInfo");
this.contactInfo = contactInfo;
}
#endregion
#region Properties
public ContactInfo ContactInfo
{
get { return contactInfo; }
}
#endregion
}
}
@@ -0,0 +1,71 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[Serializable]
public class MirandaContactSettingEventArgs : MirandaContactEventArgs
{
#region Properties
private string settingName;
public string SettingName
{
get { return settingName; }
}
private string settingOwner;
public string SettingOwner
{
get { return settingOwner; }
}
private object value;
public object Value
{
get { return value; }
}
private DatabaseSettingType valueType;
public DatabaseSettingType ValueType
{
get { return valueType; }
}
#endregion
#region .ctors
public MirandaContactSettingEventArgs(ContactInfo contactInfo, string name, string owner, object value, DatabaseSettingType valueType)
: base(contactInfo)
{
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
this.settingName = name;
this.settingOwner = owner;
this.value = value;
this.valueType = valueType;
}
#endregion
}
}
@@ -0,0 +1,373 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Virtuoso.Miranda.Plugins.Resources;
using Virtuoso.Miranda.Plugins.Collections;
using System.Collections.ObjectModel;
using Virtuoso.Hyphen;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public sealed class MirandaContext
{
#region Constants
private const string MS_SYSTEM_GETVERSIONTEXT = "Miranda/System/GetVersionText";
/// <summary>
/// Returns Miranda's RTL/CRT function poiners to malloc() free() realloc() -- 0.1.2.2+
/// This is useful for preallocation of memory for use with Miranda's services
/// that Miranda can free -- or reallocation of a block of memory passed with a service.
/// Do not use with memory unless it is explicitly expected the memory *can*
/// or *shall* be used in this way. The passed structure is expected to have it's .cbSize initialised
/// wParam=0, lParam = (LPARAM) &MM_INTERFACE.
/// </summary>
private const string MS_SYSTEM_GET_MMI = "Miranda/System/GetMMI";
#endregion
#region Fields
private static MirandaContext singleton;
private PluginManagerBase pluginManager;
private readonly ServiceCallInterceptionManager serviceInterceptors;
private readonly MirandaDatabase mirandaDatabase;
private ProtocolDictionary protocols;
private readonly MirandaPluginLink pluginLink;
private readonly ContactList contactList;
#endregion
#region .ctors
private MirandaContext(PluginManagerBase pluginManager, MirandaPluginLink mirandaLink, bool skipContextInfo)
{
if (mirandaLink == null)
throw new ArgumentNullException("mirandaLink");
this.pluginManager = pluginManager;
this.mirandaDatabase = new MirandaDatabase();
this.pluginLink = mirandaLink;
this.contactList = new ContactList();
this.serviceInterceptors = new ServiceCallInterceptionManager();
GetMMInterface();
PopulateEnvironmentInformation();
if (!skipContextInfo)
PopulateContextInformation();
else
this.protocols = new ProtocolDictionary(0);
}
/// <summary>
/// Initializes a context from a plugin link.
/// </summary>
/// <param name="mirandaLink"></param>
/// <param name="skipContextPopulation"></param>
internal static void InitializeCurrent(MirandaPluginLink mirandaLink, bool skipContextPopulation)
{
InitializeCurrent(mirandaLink, null, skipContextPopulation);
}
internal static void InitializeCurrent(MirandaPluginLink mirandaLink, PluginManagerBase pluginManager)
{
InitializeCurrent(mirandaLink, pluginManager, false);
}
[MethodImpl(MethodImplOptions.Synchronized)]
internal static void InitializeCurrent(MirandaPluginLink mirandaLink, PluginManagerBase pluginManager, bool skipContextPopulation)
{
if (singleton == null)
singleton = new MirandaContext(pluginManager, mirandaLink, skipContextPopulation);
}
[MethodImpl(MethodImplOptions.Synchronized)]
internal static void InitializeCurrent(MirandaContext context)
{
if (context == null)
throw new ArgumentNullException("context");
if (singleton == null)
singleton = context;
else
throw new InvalidOperationException();
}
[MethodImpl(MethodImplOptions.Synchronized)]
internal static void InvalidateCurrent()
{
if (Initialized)
{
singleton.DetachPluginManager();
singleton = null;
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
internal void AssociatePluginManager(PluginManagerBase manager)
{
if (manager == null)
throw new ArgumentNullException("manager");
pluginManager = manager;
}
[MethodImpl(MethodImplOptions.Synchronized)]
internal void DetachPluginManager()
{
pluginManager = null;
}
#endregion
#region Initialization
private void GetMMInterface()
{
mirandaMemoryManager = new MM_INTERFACE();
mirandaMemoryManager.Size = Marshal.SizeOf(typeof(MM_INTERFACE));
UnmanagedStructHandle<MM_INTERFACE> mmiHandle = new UnmanagedStructHandle<MM_INTERFACE>(ref mirandaMemoryManager);
try
{
if (CallService(MS_SYSTEM_GET_MMI, IntPtr.Zero, mmiHandle.IntPtr) == CallbackResult.Success)
mmiHandle.MarshalBack(out mirandaMemoryManager);
else
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MS_SYSTEM_GET_MMI, "1"));
}
finally
{
mmiHandle.Free();
}
}
internal void PopulateContextInformation()
{
PopulateNetworkProtocols();
}
private unsafe void PopulateNetworkProtocols()
{
try
{
int count;
PROTOCOLDESCRIPTOR** pointerArrayPtr;
int result = CallServiceUnsafe(MirandaServices.MS_PROTO_ENUMPROTOCOLS, &count, &pointerArrayPtr);
if (result != 0) throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MirandaServices.MS_PROTO_ENUMPROTOCOLS, result.ToString()));
ProtocolDictionary protocols = new ProtocolDictionary(count);
for (int i = 0; i < count; i++)
{
// *(ptr_to_array_of_ptrs + i * sizeof(PROTOCOLDESCRIPTOR)) = *ptr_to_ptr = *ptr = data
PROTOCOLDESCRIPTOR nativeDescriptor = **(((PROTOCOLDESCRIPTOR**)pointerArrayPtr) + i);
Protocol protocol = new Protocol(ref nativeDescriptor);
protocols.Add(protocol.Name, protocol);
}
this.protocols = protocols;
}
catch (Exception)
{
this.protocols = new ProtocolDictionary(0);
}
}
private void PopulateEnvironmentInformation()
{
InteropBuffer buffer = InteropBufferPool.AcquireBuffer();
try
{
buffer.Lock();
int result = CallService(MS_SYSTEM_GETVERSIONTEXT, buffer.SizeAsUIntPtr, buffer.IntPtr);
Debug.Assert(result == 0);
if (result == 0 && Translate.ToString(buffer.IntPtr, StringEncoding.Ansi).IndexOf("Unicode") != -1)
MirandaEnvironment.MirandaStringEncoding = StringEncoding.Unicode;
else
MirandaEnvironment.MirandaStringEncoding = StringEncoding.Ansi;
}
finally
{
buffer.Unlock();
InteropBufferPool.ReleaseBuffer(buffer);
}
MirandaEnvironment.MirandaVersion = Translate.FromMirandaVersion((uint)CallService(MirandaServices.MS_SYSTEM_GETVERSION));
}
#endregion
#region Properties
internal MirandaPluginLink PluginLink
{
get
{
return this.pluginLink;
}
}
private MM_INTERFACE mirandaMemoryManager;
internal MM_INTERFACE MirandaMemoryManager
{
get { return mirandaMemoryManager; }
}
internal PluginManagerBase PluginManager
{
get
{
if (this.pluginManager == null)
throw new InvalidOperationException("No plugin manager associated with this context.");
return this.pluginManager;
}
}
public bool HasPluginManager
{
get
{
return this.pluginManager != null;
}
}
public static MirandaContext Current
{
get
{
if (singleton == null)
throw new InvalidOperationException(TextResources.ExceptionMsg_MirandaContextNotAvailable);
return singleton;
}
}
public static bool Initialized
{
get
{
return singleton != null;
}
}
public ServiceCallInterceptionManager ServiceCallInterceptors
{
get
{
return this.serviceInterceptors;
}
}
public MirandaDatabase MirandaDatabase
{
get
{
return this.mirandaDatabase;
}
}
public ProtocolDictionary Protocols
{
get
{
return this.protocols;
}
}
public ContactList ContactList
{
get { return contactList; }
}
#endregion
#region Events
public event EventHandler ModulesLoaded;
internal void RaiseModulesLoadedEvent()
{
if (ModulesLoaded != null)
ModulesLoaded(this, EventArgs.Empty);
}
internal event EventHandler IsolatedModePluginsUnloading;
internal void RaiseIsolatedModePluginsUnloadingEvent()
{
if (IsolatedModePluginsUnloading != null)
IsolatedModePluginsUnloading(null, EventArgs.Empty);
}
#endregion
#region CallService
public int CallService(string serviceName)
{
return CallService(serviceName, UIntPtr.Zero, IntPtr.Zero, false);
}
public int CallService(string serviceName, IntPtr wParam, IntPtr lParam)
{
return CallService(serviceName, Translate.ToHandle(wParam), lParam, false);
}
[CLSCompliant(false)]
public int CallService(string serviceName, UIntPtr wParam, IntPtr lParam)
{
return CallService(serviceName, wParam, lParam, false);
}
internal int CallService(string serviceName, UIntPtr wParam, IntPtr lParam, bool noInterception)
{
if (String.IsNullOrEmpty(serviceName))
throw new ArgumentNullException("service");
int returnCode =
serviceInterceptors.RequiresInterception(serviceName) && !noInterception ?
serviceInterceptors[serviceName](wParam, lParam) : pluginLink.NativePluginLink.CallService(serviceName, wParam, lParam);
return returnCode;
}
internal unsafe int CallServiceUnsafe(string serviceName, void* wParam, void* lParam)
{
return pluginLink.CallServiceUnsafe(serviceName, wParam, lParam);
}
#endregion
}
}
@@ -0,0 +1,507 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins;
using System.Runtime.CompilerServices;
using Virtuoso.Miranda.Plugins.Native;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Virtuoso.Miranda.Plugins.Resources;
using System.Threading;
using System.Collections.ObjectModel;
using Virtuoso.Hyphen;
using Virtuoso.Miranda.Plugins.Helpers;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public sealed class MirandaDatabase : EventPublisher
{
#region Constants
private const string ME_DB_EVENT_ADDED = "DB/Event/Added",
ME_DB_EVENT_DELETED = "DB/Event/Deleted",
ME_DB_EVENT_FILTER_ADD = "DB/Event/FilterAdd",
ME_DB_CONTACT_ADDED = "DB/Contact/Added",
ME_DB_CONTACT_DELETED = "DB/Contact/Deleted",
ME_DB_CONTACT_SETTINGCHANGED = "DB/Contact/SettingChanged";
private const string MS_DB_GETPROFILENAME = "DB/GetProfileName",
MS_DB_GETPROFILEPATH = "DB/GetProfilePath",
MS_DB_EVENT_ADD = "DB/Event/Add";
private const string MS_DB_CONTACT_GETCOUNT = "DB/Contact/GetCount",
MS_DB_CONTACT_FINDFIRST = "DB/Contact/FindFirst",
MS_DB_CONTACT_FINDNEXT = "DB/Contact/FindNext";
private const string MS_DB_EVENT_FINDFIRST = "DB/Event/FindFirst",
MS_DB_EVENT_FINDNEXT = "DB/Event/FindNext";
#endregion
#region .ctors
internal MirandaDatabase() { }
#endregion
#region Event handlers
private MirandaEventHandler<MirandaDatabaseEventArgs> EventAddedEventHandler,
EventDeletedEventHandler, BeforeEventAddedEventHandler;
private MirandaEventHandler<MirandaContactEventArgs> ContactAddedEventHandler,
ContactDeletedEventHandler;
private MirandaEventHandler<MirandaContactSettingEventArgs> ContactSettingChangedEventHandler;
#endregion
#region Events & Triggers
private int RaiseDbEvent(MirandaEventHandler<MirandaDatabaseEventArgs> handler, bool fromPointer, UIntPtr wParam, IntPtr lParam)
{
if (handler == null)
return 0;
ContactInfo contactInfo = ContactInfo.FromHandle(wParam);
DatabaseEventInfo eventInfo = fromPointer ? DatabaseEventInfo.FromPointer(lParam) : DatabaseEventInfo.FromHandle(lParam);
MirandaDatabaseEventArgs eventArgs = new MirandaDatabaseEventArgs(contactInfo, eventInfo);
bool retValue = InvokeChainCancelable<MirandaDatabaseEventArgs>(handler, eventArgs);
return Convert.ToInt32(retValue);
}
public event MirandaEventHandler<MirandaDatabaseEventArgs> EventAdded
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<MirandaEventHandler<MirandaDatabaseEventArgs>>(ref EventAddedEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_DB_EVENT_ADDED,
delegate(UIntPtr wParam, IntPtr lParam)
{
return RaiseDbEvent(EventAddedEventHandler, false, wParam, lParam);
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<MirandaEventHandler<MirandaDatabaseEventArgs>>(ref EventAddedEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_DB_EVENT_ADDED, EventAddedEventHandler);
}
}
public event MirandaEventHandler<MirandaDatabaseEventArgs> EventDeleted
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<MirandaEventHandler<MirandaDatabaseEventArgs>>(ref EventDeletedEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_DB_EVENT_DELETED,
delegate(UIntPtr wParam, IntPtr lParam)
{
return RaiseDbEvent(EventDeletedEventHandler, false, wParam, lParam);
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<MirandaEventHandler<MirandaDatabaseEventArgs>>(ref EventDeletedEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_DB_EVENT_DELETED, EventDeletedEventHandler);
}
}
/// <summary>
/// Return TRUE to filter out the event, FALSE to pass the message along.
/// </summary>
public event MirandaEventHandler<MirandaDatabaseEventArgs> BeforeEventAdded
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<MirandaEventHandler<MirandaDatabaseEventArgs>>(ref BeforeEventAddedEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_DB_EVENT_FILTER_ADD,
delegate(UIntPtr wParam, IntPtr lParam)
{
return RaiseDbEvent(BeforeEventAddedEventHandler, true, wParam, lParam);
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<MirandaEventHandler<MirandaDatabaseEventArgs>>(ref BeforeEventAddedEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_DB_EVENT_FILTER_ADD, BeforeEventAddedEventHandler);
}
}
private int RaiseContactEvent(MirandaEventHandler<MirandaContactEventArgs> handler, UIntPtr wParam)
{
if (handler == null)
return 0;
ContactInfo contactInfo = GetContactInfo(wParam);
MirandaContactEventArgs eventArgs = new MirandaContactEventArgs(contactInfo);
bool retValue = InvokeChainCancelable<MirandaContactEventArgs>(handler, eventArgs);
return Convert.ToInt32(retValue);
}
private static ContactInfo GetContactInfo(UIntPtr wParam)
{
if (wParam == UIntPtr.Zero)
return ContactInfo.MeNeutral;
else
return ContactInfo.FromHandle(wParam);
}
private unsafe int RaiseContactSettingEvent(UIntPtr hContact, IntPtr pDbWriteSetting)
{
DBCONTACTWRITESETTING dbWriteSetting = *(DBCONTACTWRITESETTING*)pDbWriteSetting.ToPointer();
ContactInfo contactInfo = GetContactInfo(hContact);
string name = Translate.ToString(dbWriteSetting.Name, StringEncoding.Ansi);
string moduleName = Translate.ToString(dbWriteSetting.Module, StringEncoding.Ansi);
object value = null;
if ((DatabaseSettingType)dbWriteSetting.Value.Type != DatabaseSettingType.Blob)
value = DBCONTACTWRITESETTING.ExtractValue(pDbWriteSetting);
else
Debugger.Log(10, Loader.LogCategory, "Blob settings are not yet supported, the value will be null.");
MirandaContactSettingEventArgs eventArgs = new MirandaContactSettingEventArgs(contactInfo, name, moduleName, value, (DatabaseSettingType)dbWriteSetting.Value.Type);
bool retValue = InvokeChainCancelable<MirandaContactSettingEventArgs>(ContactSettingChangedEventHandler, eventArgs);
return Convert.ToInt32(retValue);
}
public event MirandaEventHandler<MirandaContactEventArgs> ContactAdded
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<MirandaEventHandler<MirandaContactEventArgs>>(ref ContactAddedEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_DB_CONTACT_ADDED,
delegate(UIntPtr wParam, IntPtr lParam)
{
return RaiseContactEvent(ContactAddedEventHandler, wParam);
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<MirandaEventHandler<MirandaContactEventArgs>>(ref ContactAddedEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_DB_CONTACT_ADDED, ContactAddedEventHandler);
}
}
public event MirandaEventHandler<MirandaContactEventArgs> ContactDeleted
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<MirandaEventHandler<MirandaContactEventArgs>>(ref ContactDeletedEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_DB_CONTACT_DELETED,
delegate(UIntPtr wParam, IntPtr lParam)
{
return RaiseContactEvent(ContactDeletedEventHandler, wParam);
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<MirandaEventHandler<MirandaContactEventArgs>>(ref ContactDeletedEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_DB_CONTACT_DELETED, ContactDeletedEventHandler);
}
}
public event MirandaEventHandler<MirandaContactSettingEventArgs> ContactSettingChanged
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<MirandaEventHandler<MirandaContactSettingEventArgs>>(ref ContactSettingChangedEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_DB_CONTACT_SETTINGCHANGED,
delegate(UIntPtr wParam, IntPtr lParam)
{
return RaiseContactSettingEvent(wParam, lParam);
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<MirandaEventHandler<MirandaContactSettingEventArgs>>(ref ContactSettingChangedEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_DB_CONTACT_SETTINGCHANGED, ContactSettingChangedEventHandler);
}
}
#endregion
#region Properties
#region Profile
public string ProfileName
{
get
{
InteropBuffer buffer = InteropBufferPool.AcquireBuffer();
try
{
buffer.Lock();
int result = MirandaContext.Current.CallService(MS_DB_GETPROFILENAME, buffer.SizeAsUIntPtr, buffer.IntPtr);
Debug.Assert(result == 0);
if (result != 0) return null;
return Translate.ToString(buffer.IntPtr, StringEncoding.Ansi);
}
catch (Exception e)
{
throw new MirandaException(TextResources.ExceptionMsg_ErrorWhileCallingMirandaService, e);
}
finally
{
buffer.Unlock();
InteropBufferPool.ReleaseBuffer(buffer);
}
}
}
public string ProfilePath
{
get
{
InteropBuffer buffer = InteropBufferPool.AcquireBuffer();
try
{
buffer.Lock();
int result = MirandaContext.Current.CallService(MS_DB_GETPROFILEPATH, buffer.SizeAsUIntPtr, buffer.IntPtr);
Debug.Assert(result == 0);
if (result != 0) return null;
return Translate.ToString(buffer.IntPtr, StringEncoding.Ansi);
}
catch (Exception e)
{
throw new MirandaException(TextResources.ExceptionMsg_ErrorWhileCallingMirandaService, e);
}
finally
{
buffer.Unlock();
InteropBufferPool.ReleaseBuffer(buffer);
}
}
}
#endregion
#endregion
#region Methods
#region Contacts
/// <summary>
/// Enumerates contact handles, excluding the Me contact.
/// </summary>
/// <returns>Contact handles.</returns>
public IEnumerable<IntPtr> GetContactHandles()
{
MirandaContext context = MirandaContext.Current;
Callback findNext = ServiceManager.GetService(MS_DB_CONTACT_FINDNEXT);
UIntPtr handle = (UIntPtr)(uint)context.CallService(MS_DB_CONTACT_FINDFIRST);
do
{
if (handle != UIntPtr.Zero)
yield return Translate.ToHandle(handle);
}
while ((handle = (UIntPtr)(uint)findNext(handle, IntPtr.Zero)) != UIntPtr.Zero);
}
public ReadOnlyCollection<ContactInfo> GetContacts()
{
return GetContacts(false);
}
public ReadOnlyCollection<ContactInfo> GetContacts(bool includeSelf)
{
MirandaContext context = MirandaContext.Current;
Callback findNext = ServiceManager.GetService(MS_DB_CONTACT_FINDNEXT);
List<ContactInfo> contacts = new List<ContactInfo>(context.CallService(MS_DB_CONTACT_GETCOUNT));
if (includeSelf)
contacts.Add(ContactInfo.MeNeutral);
foreach (IntPtr handle in GetContactHandles())
contacts.Add(ContactInfo.FromHandle(handle));
return contacts.AsReadOnly();
}
public ContactInfo FindContact(string uuid)
{
return FindContact(uuid, ContactInfoProperty.UniqueID, StringEncoding.Ansi);
}
public ContactInfo FindContact(string searchValue, ContactInfoProperty searchCriterion, StringEncoding valueEncoding)
{
return FindContact(searchValue, searchCriterion, valueEncoding, StringComparison.Ordinal);
}
public ContactInfo FindContact(string searchValue, ContactInfoProperty searchCriterion, StringEncoding valueEncoding, StringComparison comparisonType)
{
if (searchValue == null)
throw new ArgumentNullException("searchValues");
foreach (IntPtr handle in GetContactHandles())
{
object value;
ContactInfoPropertyType type;
if (ContactInfo.GetProperty(handle, searchCriterion, out value, out type)
&& searchValue.Equals(value.ToString(), comparisonType))
return ContactInfo.FromHandle(handle);
}
Debug.Assert(false);
return null;
}
public ContactInfo[] FindContacts(params string[] uuids)
{
if (uuids == null)
throw new ArgumentNullException("uuids");
List<ContactInfo> results = new List<ContactInfo>(uuids.Length);
foreach (string uuid in uuids)
{
ContactInfo contact = FindContact(uuid, ContactInfoProperty.UniqueID, StringEncoding.Ansi);
if (contact != null)
results.Add(contact);
}
return results.ToArray();
}
#endregion
#region Events
public IntPtr AddEvent(ContactInfo associatedContact, object data, ISettingOwner owner, DatabaseEventType type, DatabaseEventProperties flags, DateTime? timestamp)
{
return AddEvent(associatedContact, data, owner, type, flags, timestamp, true);
}
public IntPtr AddEvent(ContactInfo associatedContact, object data, ISettingOwner owner, DatabaseEventType type, DatabaseEventProperties flags, DateTime? timestamp, bool throwOnFailure)
{
if (owner == null)
throw new ArgumentNullException("owner");
return AddEvent(associatedContact, data, owner.Name, type, flags, timestamp, throwOnFailure);
}
public IntPtr AddEvent(ContactInfo associatedContact, object data, string owner, DatabaseEventType type, DatabaseEventProperties flags, DateTime? timestamp, bool throwOnFailure)
{
if (associatedContact == null)
throw new ArgumentNullException("associatedContact");
if (String.IsNullOrEmpty(owner))
throw new ArgumentNullException("owner");
if (data == null)
throw new ArgumentNullException("data");
IntPtr pBlob = IntPtr.Zero;
UnmanagedStructHandle<DBEVENTINFO> nativeStruct = UnmanagedStructHandle<DBEVENTINFO>.Empty;
try
{
int totalBytes;
if (data is string)
{
totalBytes = DBEVENTINFO.LayoutAnsiUniString((string)data, out pBlob);
}
else if (data is byte[])
{
byte[] dataBytes = (byte[])data;
totalBytes = dataBytes.Length;
pBlob = Marshal.AllocHGlobal(totalBytes);
Marshal.Copy(dataBytes, 0, pBlob, dataBytes.Length);
}
else
throw new ArgumentOutOfRangeException("data");
DBEVENTINFO info = new DBEVENTINFO(0, IntPtr.Zero);
info.Module = Translate.ToHandle(owner, StringEncoding.Ansi).IntPtr;
info.BlobSize = (uint)totalBytes;
info.BlobPtr = pBlob;
info.EventType = (ushort)type;
info.Flags = (uint)flags;
info.Timestamp = Utilities.GetTimestamp(timestamp.HasValue ? timestamp.Value : DateTime.Now);
nativeStruct = new UnmanagedStructHandle<DBEVENTINFO>(ref info, pBlob, info.Module);
IntPtr eventHandle = (IntPtr)MirandaContext.Current.CallService(MS_DB_EVENT_ADD, associatedContact.MirandaHandle, nativeStruct.IntPtr);
if (eventHandle == IntPtr.Zero && throwOnFailure)
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MS_DB_EVENT_ADD, eventHandle.ToString()));
else
return eventHandle;
}
finally
{
nativeStruct.Free();
}
}
public IEnumerable<IntPtr> GetEventHandles(ContactInfo owner)
{
if (owner == null)
throw new ArgumentNullException("owner");
return GetEventHandles(owner.MirandaHandle);
}
public IEnumerable<IntPtr> GetEventHandles(IntPtr ownerHandle)
{
Callback findNext = ServiceManager.GetService(MS_DB_EVENT_FINDNEXT);
IntPtr pEvent = (IntPtr)MirandaContext.Current.CallService(MS_DB_EVENT_FINDFIRST, ownerHandle, IntPtr.Zero);
while (pEvent != IntPtr.Zero)
{
yield return pEvent;
pEvent = (IntPtr)findNext(Translate.ToHandle(pEvent), IntPtr.Zero);
}
}
#endregion
#endregion
}
}
@@ -0,0 +1,49 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[Serializable]
public class MirandaDatabaseEventArgs : MirandaContactEventArgs
{
#region .ctors
public MirandaDatabaseEventArgs(ContactInfo contact, DatabaseEventInfo eventInfo) : base(contact)
{
if (eventInfo == null)
throw new ArgumentNullException("eventInfo");
this.eventInfo = eventInfo;
}
#endregion
#region Properties
private readonly DatabaseEventInfo eventInfo;
public DatabaseEventInfo EventInfo
{
get { return eventInfo; }
}
#endregion
}
}
@@ -0,0 +1,123 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using System.IO;
using Virtuoso.Hyphen;
using System.Windows.Forms;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public static class MirandaEnvironment
{
#region Fields
private static Version mirandaVersion;
private static StringEncoding mirandaStringEncoding;
internal const string MirandaPluginsFolderRelativePath = @"plugins\",
ManagedPluginsFolderName = "managed",
ManagedPluginsFolderRelativePath = MirandaPluginsFolderRelativePath + ManagedPluginsFolderName;
private static readonly string mirandaFolderPath = Application.StartupPath,
mirandaPluginsFolderPath = Path.Combine(mirandaFolderPath, MirandaPluginsFolderRelativePath),
managedPluginsFolderPath = Path.Combine(mirandaFolderPath, ManagedPluginsFolderRelativePath),
mirandaBootIniPath = mirandaFolderPath + @"\MirandaBoot.ini";
#endregion
#region Methods
public static string GetManagedSubdirectoryRelativePath(string subDir)
{
return Path.Combine(ManagedPluginsFolderRelativePath, subDir);
}
#endregion
#region Properties
public static StringEncoding MirandaStringEncoding
{
get
{
return mirandaStringEncoding;
}
internal set
{
mirandaStringEncoding = value;
}
}
public static string MirandaFolderPath
{
get
{
return mirandaFolderPath;
}
}
public static string MirandaPluginsFolderPath
{
get
{
return mirandaPluginsFolderPath;
}
}
public static string ManagedPluginsFolderPath
{
get
{
return managedPluginsFolderPath;
}
}
public static Version MirandaVersion
{
get
{
return mirandaVersion;
}
internal set
{
mirandaVersion = value;
}
}
public static Version HyphenVersion
{
get
{
return Loader.HyphenVersion;
}
}
public static string MirandaBootIniPath
{
get
{
return mirandaBootIniPath;
}
}
#endregion
}
}
@@ -0,0 +1,29 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[Serializable]
public abstract class MirandaEventArgs : EventArgs
{
protected MirandaEventArgs() { }
}
}
@@ -0,0 +1,32 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
/// <summary>
/// Represents a generic handler for Miranda-raised events.
/// </summary>
/// <typeparam name="TEventArgs">Type of EventArgs.</typeparam>
/// <param name="sender">Sender of the event.</param>
/// <param name="e">Event arguments.</param>
/// <returns>TRUE to block the event from bubbling to another subscribers, FALSE to pass it along.</returns>
public delegate bool MirandaEventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs : MirandaEventArgs;
}
@@ -0,0 +1,35 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
internal static class MirandaEvents
{
public const string ME_SYSTEM_SHUTDOWN = "Miranda/System/Shutdown",
ME_SYSTEM_OKTOEXIT = "Miranda/System/OkToExitEvent",
ME_DB_EVENT_ADDED = "DB/Event/Added",
ME_DB_EVENT_DELETED = "DB/Event/Deleted",
ME_DB_CONTACT_ADDED = "DB/Contact/Added",
ME_DB_CONTACT_DELETED = "DB/Contact/Deleted",
ME_DB_CONTACT_SETTINGCHANGED = "DB/Contact/SettingChanged",
ME_SYSTEM_MODULESLOADED = "Miranda/System/ModulesLoaded";
}
}
@@ -0,0 +1,73 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public enum ItemType : int
{
Unspecified,
Contact,
Group
}
public class MirandaItem : MirandaObject
{
#region Fields
private static readonly Type ItemTypeType = typeof(ItemType);
private ItemType type;
#endregion
#region .ctors
protected MirandaItem(IntPtr handle, ItemType type) : this(handle)
{
if (!Enum.IsDefined(ItemTypeType, type))
throw new ArgumentOutOfRangeException("type");
if (type == ItemType.Unspecified)
throw new ArgumentException("Unspecified type is not supported.");
this.type = type;
}
internal MirandaItem(IntPtr handle)
{
this.MirandaHandle = handle;
}
#endregion
#region Properties
public ItemType Type
{
get
{
return this.type;
}
}
#endregion
}
}
@@ -0,0 +1,48 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public abstract class MirandaObject : IMirandaObject
{
#region Fields
private IntPtr mirandaHandle;
#endregion
#region .ctors
protected MirandaObject() { }
#endregion
#region Properties
public IntPtr MirandaHandle
{
get { return mirandaHandle; }
protected internal set { mirandaHandle = value; }
}
#endregion
}
}
@@ -0,0 +1,44 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Virtuoso.Miranda.Plugins.Resources;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
internal static class MirandaServices
{
public const string MS_CLIST_ADDMAINMENUITEM = "CList/AddMainMenuItem",
MS_CLIST_ADDCONTACTMENUITEM = "CList/AddContactMenuItem",
MS_CLIST_MODIFYMENUITEM = "CList/ModifyMenuItem",
MS_CLIST_SYSTRAY_NOTIFY = "Miranda/Systray/Notify",
MS_CONTACT_GETCONTACTINFO = "Miranda/Contact/GetContactInfo",
MS_PROTO_GETCONTACTBASEPROTO = "Proto/GetContactBaseProto",
MS_PROTO_ENUMPROTOCOLS = "Proto/EnumProtocols",
MS_PROTO_CALLCONTACTSERVICE = "Proto/CallContactService",
MS_PROTO_REGISTERMODULE = "Proto/RegisterModule",
PS_MESSAGE = "/SendMsg",
MS_SYSTEM_GETVERSION = "Miranda/System/GetVersion";
}
}
@@ -0,0 +1,277 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Runtime.Serialization.Formatters.Binary;
using Virtuoso.Miranda.Plugins.Collections;
using Virtuoso.Miranda.Plugins.Configuration;
using Virtuoso.Miranda.Plugins.Helpers;
using Virtuoso.Miranda.Plugins.Resources;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[Serializable]
public abstract class PluginConfiguration
{
#region Fields
private static readonly object SyncObject = new object();
private static readonly TypeInstanceCache<IStorage> Stores = new TypeInstanceCache<IStorage>();
private static readonly TypeInstanceCache<IEncryption> Encryptions = new TypeInstanceCache<IEncryption>();
internal readonly ConfigurationValues values;
private bool isDirty;
#endregion
#region .ctors
protected PluginConfiguration()
{
values = new ConfigurationValues();
}
protected virtual void InitializeDefaultConfiguration() { }
#endregion
#region Events
[field: NonSerialized]
public event EventHandler ConfigurationChanged;
protected void RaiseChangedEvent()
{
if (ConfigurationChanged != null)
ConfigurationChanged(this, EventArgs.Empty);
}
#endregion
#region Properties
public ConfigurationValues Values
{
get
{
return values;
}
}
public bool IsDirty
{
get
{
return isDirty;
}
protected internal set
{
isDirty = value;
}
}
#endregion
#region Methods
protected virtual void OnBeforeSerialization() { }
protected virtual void OnAfterDeserialization() { }
protected void MarkDirty()
{
IsDirty = true;
RaiseChangedEvent();
}
#region Helpers
private static ConfigurationOptionsAttribute GetOptions(Type configType)
{
if (configType == null)
throw new ArgumentNullException("configType");
ConfigurationOptionsAttribute options = null;
Type configAttribType = typeof(ConfigurationOptionsAttribute);
if (configType.IsDefined(configAttribType, false))
options = (ConfigurationOptionsAttribute)configType.GetCustomAttributes(configAttribType, false)[0];
else
options = new ConfigurationOptionsAttribute();
return options.Finalize();
}
private static byte[] FetchStream(Stream stream)
{
if (stream == null)
throw new ArgumentNullException("stream");
if (!stream.CanRead)
throw new ArgumentException();
byte[] buffer = new byte[stream.Length];
if (stream.Read(buffer, 0, buffer.Length) != stream.Length)
throw new IOException();
return buffer;
}
internal static void FlushCaches()
{
lock (SyncObject)
{
foreach (IStorage storage in Stores.Values)
storage.Dispose();
Stores.Clear();
Encryptions.Clear();
}
}
#endregion
#region Save
public void Save()
{
try
{
lock (SyncObject)
{
OnBeforeSerialization();
ConfigurationOptionsAttribute options = GetOptions(GetType());
IStorage storage = Stores.Instantiate(options.Storage);
if (options.Encrypt)
SerializeEncrypted(storage, options);
else
Serialize(storage, options);
}
}
catch (IsolatedStorageException isE)
{
throw new ConfigurationException(TextResources.ExceptionMsg_UnableToSaveConfiguration_StorageError, isE);
}
}
private void Serialize(IStorage storage, ConfigurationOptionsAttribute options)
{
BinaryFormatter serializer = new BinaryFormatter();
using (Stream stream = storage.OpenWrite(GetType(), options))
serializer.Serialize(stream, this);
}
private void SerializeEncrypted(IStorage storage, ConfigurationOptionsAttribute options)
{
IEncryption encryption = Encryptions.Instantiate(options.Encryption);
using (Stream serializationStream = new MemoryStream(2048))
{
new BinaryFormatter().Serialize(serializationStream, this);
serializationStream.Seek(0, SeekOrigin.Begin);
byte[] data = FetchStream(serializationStream);
byte[] protectedData = encryption.Encrypt(data);
using (Stream stream = storage.OpenWrite(GetType(), options))
stream.Write(protectedData, 0, protectedData.Length);
}
}
#endregion
#region Load
public static T Load<T>() where T : PluginConfiguration
{
try
{
lock (SyncObject)
{
Type configType = typeof(T);
ConfigurationOptionsAttribute options = GetOptions(configType);
IStorage storage = Stores.Instantiate(options.Storage);
if (!storage.Exists(configType, options))
return GetDefaultConfiguration<T>();
using (Stream stream = storage.OpenRead(configType, options))
{
T result = null;
if (options.Encrypt)
result = DeserializeEncrypted<T>(stream, options);
else
result = Deserialize<T>(stream);
result.OnAfterDeserialization();
return result;
}
}
}
catch (OperationCanceledException e)
{
throw new ConfigurationException(TextResources.ExceptionMsg_UnableToLoadConfiguration_StorageError, e);
}
catch (Exception e)
{
T defaults = GetDefaultConfiguration<T>();
defaults.Save();
throw new ConfigurationException(TextResources.ExceptionMsg_UnableToLoadConfiguration_StorageError, e);
}
}
private static T Deserialize<T>(Stream stream) where T : PluginConfiguration
{
return new BinaryFormatter().Deserialize(stream) as T;
}
private static T DeserializeEncrypted<T>(Stream stream, ConfigurationOptionsAttribute options) where T : PluginConfiguration
{
byte[] protectedData = FetchStream(stream);
byte[] data = Encryptions.Instantiate(options.Encryption).Decrypt(protectedData);
using (Stream serializedStream = new MemoryStream(data))
return new BinaryFormatter().Deserialize(serializedStream) as T;
}
public static TConfig GetDefaultConfiguration<TConfig>() where TConfig : PluginConfiguration
{
TConfig result = Activator.CreateInstance(typeof(TConfig), true) as TConfig;
if (result == null)
throw new ConfigurationException();
result.InitializeDefaultConfiguration();
return result;
}
#endregion
#endregion
}
}
+225
View File
@@ -0,0 +1,225 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using System.Runtime.InteropServices;
using Virtuoso.Miranda.Plugins.Resources;
using Virtuoso.Hyphen;
using System.Runtime.CompilerServices;
using Virtuoso.Miranda.Plugins.Infrastructure.Protocols;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public class Protocol : ContextWorker, ISettingOwner
{
#region Constants
internal const string PS_GETSTATUS = "/GetStatus";
internal const string PS_SETSTATUS = "/SetStatus";
internal const string PS_GETCAPS = "/GetCaps";
internal const string PS_GETNAME = "/GetName";
internal const string PS_LOADICON = "/LoadIcon";
internal const string PSS_MESSAGE = "/SendMsg";
private const string MS_PROTO_ISPROTOONCONTACT = "Proto/IsProtoOnContact";
#endregion
#region Fields
private static readonly Protocol unknownProtocol = new Protocol();
private readonly string name;
private readonly ProtocolType type;
#endregion
#region .ctors
internal Protocol()
{
this.name = String.Empty;
this.type = ProtocolType.Other;
}
internal Protocol(string name, ProtocolType type)
{
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
if (!Enum.IsDefined(typeof(ProtocolType), type))
throw new ArgumentOutOfRangeException("type");
this.name = name;
this.type = type;
}
internal Protocol(ref PROTOCOLDESCRIPTOR descriptor)
{
if (descriptor.Name == IntPtr.Zero)
throw new ArgumentException();
this.name = Translate.ToString(descriptor.Name, StringEncoding.Ansi);
this.type = (ProtocolType)descriptor.Type;
}
~Protocol()
{
if (namePtr.IsValid)
namePtr.Free();
}
#endregion
#region Events
private static MirandaEventHandler<ProtocolStatusChangeEventArgs> StatusChangedEventHandler;
public static event MirandaEventHandler<ProtocolStatusChangeEventArgs> StatusChanged
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
// Important to check to not hook the Ack for nothing
if (value == null)
throw new ArgumentNullException("value");
// First subscriber?
if (StatusChangedEventHandler == null)
AckRouter.AckReceived += AckRouter_AckReceived;
LazyEventBinder.AttachDelegate<MirandaEventHandler<ProtocolStatusChangeEventArgs>>(ref StatusChangedEventHandler, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<MirandaEventHandler<ProtocolStatusChangeEventArgs>>(ref StatusChangedEventHandler, value);
// No more subscribers?
if (StatusChangedEventHandler == null)
AckRouter.AckReceived -= AckRouter_AckReceived;
}
}
private static bool AckRouter_AckReceived(object sender, AckEventArgs e)
{
if (e.Type == AckType.Status)
{
if (StatusChangedEventHandler != null)
StatusChangedEventHandler(e.Protocol, new ProtocolStatusChangeEventArgs(e.Protocol, (StatusMode)e.LParam));
}
return EventResult.HonourEventChain;
}
#endregion
#region Methods
private void CheckUnknown()
{
if (String.IsNullOrEmpty(name))
throw new InvalidOperationException(TextResources.ExceptionMsg_CallInvalidForUnknownNetworkProtocol);
}
[CLSCompliant(false)]
public int CallProtocolService(string serviceName, UIntPtr wParam, IntPtr lParam)
{
if (serviceName == null)
throw new ArgumentNullException("serviceName");
CheckUnknown();
return MirandaContext.Current.CallService(GetProtoServiceName(serviceName), wParam, lParam);
}
public string GetProtoServiceName(string service)
{
if (service == null)
throw new ArgumentNullException("service");
return String.Format("{0}{1}", Name, service);
}
public bool HasInChain(ContactInfo contact)
{
if (contact == null)
throw new ArgumentNullException("contact");
return HasInChain(contact.MirandaHandle);
}
public bool HasInChain(IntPtr contactHandle)
{
return Convert.ToBoolean(Context.CallService(MS_PROTO_ISPROTOONCONTACT, contactHandle, NamePtr));
}
#endregion
#region Properties
public static Protocol UnknownProtocol
{
get { return Protocol.unknownProtocol; }
}
public StatusMode Status
{
get
{
return (StatusMode)CallProtocolService(PS_GETSTATUS, UIntPtr.Zero, IntPtr.Zero);
}
set
{
CallProtocolService(PS_SETSTATUS, (UIntPtr)value, IntPtr.Zero);
}
}
public string Name
{
get { return name; }
}
public ProtocolType Type
{
get { return type; }
}
public bool IsUnknown
{
get
{
return object.ReferenceEquals(this, UnknownProtocol);
}
}
private UnmanagedStringHandle namePtr;
protected virtual IntPtr NamePtr
{
get
{
if (!namePtr.IsValid)
namePtr = Translate.ToHandle(Name, StringEncoding.Ansi);
return namePtr.IntPtr;
}
}
#endregion
}
}
@@ -0,0 +1,74 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Virtuoso.Miranda.Plugins.Native;
using Virtuoso.Miranda.Plugins.Resources;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public static class ProtocolStatus
{
#region Fields
private const string MS_AWAYMSG_SHOWAWAYMSG = "SRAway/GetMessage",
MS_AWAYMSG_GETSTATUSMSG = "SRAway/GetStatusMessage";
#endregion
#region Methods
public static bool ShowAwayMessage(ContactInfo contact)
{
int result = MirandaContext.Current.CallService(MS_AWAYMSG_SHOWAWAYMSG, contact.MirandaHandle, IntPtr.Zero);
Debug.Assert(result == 0);
return result == 0;
}
public static string GetStatusMessage(StatusMode status)
{
if (!Enum.IsDefined(typeof(StatusMode), status))
throw new ArgumentOutOfRangeException("status");
IntPtr statusPtr = IntPtr.Zero;
try
{
statusPtr = (IntPtr)MirandaContext.Current.CallService(MS_AWAYMSG_GETSTATUSMSG, (UIntPtr)(ulong)status, IntPtr.Zero);
if (statusPtr == IntPtr.Zero) return null;
return Translate.ToString(statusPtr, Virtuoso.Miranda.Plugins.Native.StringEncoding.Ansi);
}
catch (Exception e)
{
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MS_AWAYMSG_GETSTATUSMSG, 0), e);
}
finally
{
if (statusPtr != IntPtr.Zero)
Marshal.FreeHGlobal(statusPtr);
}
}
#endregion
}
}
@@ -0,0 +1,52 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public class ProtocolStatusChangeEventArgs : MirandaEventArgs
{
#region Properties
private StatusMode newStatus;
public StatusMode NewStatus
{
get { return newStatus; }
}
private Protocol protocol;
public Protocol Protocol
{
get { return protocol; }
}
#endregion
#region .ctors
public ProtocolStatusChangeEventArgs(Protocol protocol, StatusMode newStatus)
{
this.newStatus = newStatus;
this.protocol = protocol;
}
#endregion
}
}
@@ -0,0 +1,90 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using System.Threading;
using System.Security;
namespace Virtuoso.Miranda.Plugins.Infrastructure.Protocols
{
[SuppressUnmanagedCodeSecurity]
public static class AckBroadcaster
{
#region Constants
private const string MS_PROTO_BROADCASTACK = "Proto/BroadcastAck";
#endregion
#region Helpers
private static ACKDATA BuildAckData(IntPtr pModuleName, AckType type, bool success, IntPtr contactHandle, IntPtr processHandle, IntPtr lParam)
{
ACKDATA ack = new ACKDATA(pModuleName, (int)type, success ? (int)AckResult.Success : (int)AckResult.Failure);
ack.ContactHandle = contactHandle;
ack.ProcessHandle = processHandle;
ack.LParam = lParam;
return ack;
}
private static unsafe int BroadcastAck(ACKDATA* ack)
{
return MirandaContext.Current.CallServiceUnsafe(MS_PROTO_BROADCASTACK, null, ack);
}
#endregion
#region Methods
public static int BroadcastAck(string moduleName, AckType type, bool success, IntPtr contactHandle, IntPtr processHandle, IntPtr lParam)
{
UnmanagedStringHandle pModuleName = UnmanagedStringHandle.Empty;
try
{
pModuleName = new UnmanagedStringHandle(moduleName, StringEncoding.Ansi);
return BroadcastAck(pModuleName.IntPtr, type, success, contactHandle, processHandle, lParam);
}
finally
{
pModuleName.Free();
}
}
public static unsafe void BroadcastMessageAckAsync(IntPtr pModuleName, bool success, IntPtr contactHandle, int processCookie)
{
ACKDATA ack = BuildAckData(pModuleName, AckType.Message, success, contactHandle, (IntPtr)processCookie, IntPtr.Zero);
ThreadPool.QueueUserWorkItem(delegate(object ackObject)
{
ACKDATA _ack = (ACKDATA)ackObject;
BroadcastAck(&_ack);
}, ack);
}
public static unsafe int BroadcastAck(IntPtr pModuleName, AckType type, bool success, IntPtr contactHandle, IntPtr processHandle, IntPtr lParam)
{
ACKDATA ack = BuildAckData(pModuleName, type, success, contactHandle, processHandle, lParam);
return BroadcastAck(&ack);
}
#endregion
}
}
@@ -0,0 +1,48 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure.Protocols
{
public enum AckType : int
{
Message = 0,
Url = 1,
File = 2,
Chat = 3,
AwayMessage = 4,
AuthorizationRequest = 5,
Added = 6,
GetInfo = 7,
SetInfo = 8,
Login = 9,
Search = 10,
NewUser = 11,
Status = 12,
Contacts = 13, //send/recv of contacts
Avatar = 14, //send/recv of avatars from a protocol
}
public enum AckResult : int
{
Success = 0,
Failure = 1,
}
}
@@ -0,0 +1,93 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
namespace Virtuoso.Miranda.Plugins.Infrastructure.Protocols
{
public sealed class AckEventArgs : MirandaEventArgs
{
#region Properties
private Protocol protocol;
public Protocol Protocol
{
get { return protocol; }
}
private ContactInfo contact;
public ContactInfo Contact
{
get { return contact; }
}
private AckType type;
public AckType Type
{
get { return type; }
}
private AckResult result;
public AckResult Result
{
get { return result; }
}
private IntPtr processHandle;
public IntPtr ProcessHandle
{
get { return processHandle; }
}
private IntPtr lParam;
public IntPtr LParam
{
get { return lParam; }
}
#endregion
#region .ctors
public AckEventArgs() { }
internal unsafe static AckEventArgs FromACKDATA(IntPtr pAckData)
{
if (pAckData == IntPtr.Zero)
throw new ArgumentNullException("pAckData");
ACKDATA ackData = *(ACKDATA*)pAckData.ToPointer();
AckEventArgs ackArgs = new AckEventArgs();
ackArgs.contact = ContactInfo.FromHandle(ackData.ContactHandle);
ackArgs.lParam = ackData.LParam;
ackArgs.processHandle = ackData.ProcessHandle;
ackArgs.result = (AckResult)ackData.Result;
ackArgs.type = (AckType)ackData.Type;
if (ackData.ModuleName != IntPtr.Zero)
ackArgs.protocol = MirandaContext.Current.Protocols[Translate.ToString(ackData.ModuleName, StringEncoding.Ansi)];
return ackArgs;
}
#endregion
}
}
@@ -0,0 +1,125 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.CompilerServices;
namespace Virtuoso.Miranda.Plugins.Infrastructure.Protocols
{
public static class AckRouter
{
#region Constants
/// <summary>
/// Call the next service in the chain for this send operation.
/// wParam=wParam
/// lParam=lParam
/// The return value should be returned immediately
/// wParam and lParam should be passed as the parameters that your service was
/// called with. wParam must remain untouched but lParam is a CCSDATA structure
/// that can be copied and modified if needed.
/// Typically, the last line of any chaining protocol function is
/// return CallService(MS_PROTO_CHAINSEND,wParam,lParam);
/// </summary>
private const string MS_PROTO_CHAINSEND = "Proto/ChainSend";
/// <summary>
/// Call the next service in the chain for this receive operation
/// wParam=wParam
/// lParam=lParam
/// The return value should be returned immediately
/// wParam and lParam should be passed as the parameters that your service was
/// called with. wParam must remain untouched but lParam is a CCSDATA structure
/// that can be copied and modified if needed.
/// When being initiated by the network-access protocol module, wParam should be
/// zero.
/// Thread safety: ms_proto_chainrecv is completely thread safe since 0.1.2.0
/// Calls to it are translated to the main thread and passed on from there. The
/// function will not return until all callees have returned, irrepective of
/// differences between threads the functions are in.
/// </summary>
private const string MS_PROTO_CHAINRECV = "Proto/ChainRecv";
#endregion
#region Fields
private const string ME_PROTO_ACK = "Proto/Ack";
private static MirandaEventHandler<AckEventArgs> AckReceivedEventHandler;
#endregion
#region Events
public static event MirandaEventHandler<AckEventArgs> AckReceived
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
LazyEventBinder.AttachDelegate<MirandaEventHandler<AckEventArgs>>(ref AckReceivedEventHandler, value);
LazyEventBinder.HookMirandaEvent(ME_PROTO_ACK,
delegate(UIntPtr wParam, IntPtr lParam)
{
AckEventArgs e = AckEventArgs.FromACKDATA(lParam);
EventPublisher.InvokeChainCancelable<AckEventArgs>(AckReceivedEventHandler, null, e);
return (int)CallbackResult.Success;
});
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
LazyEventBinder.DetachDelegate<MirandaEventHandler<AckEventArgs>>(ref AckReceivedEventHandler, value);
LazyEventBinder.UnhookMirandaEvent(ME_PROTO_ACK, AckReceivedEventHandler);
}
}
#endregion
#region Methods
public static int ChainSend(ContactChainData chainData)
{
if (chainData == null)
throw new ArgumentNullException("chainData");
return ChainSend(chainData.WParam, chainData.CcsDataPtr);
}
public static int ChainSend(UIntPtr wParam, IntPtr lParam)
{
return MirandaContext.Current.CallService(MS_PROTO_CHAINSEND, wParam, lParam);
}
public static int ChainReceive(ContactChainData chainData)
{
if (chainData == null)
throw new ArgumentNullException("chainData");
return ChainReceive(chainData.WParam, chainData.CcsDataPtr);
}
public static int ChainReceive(UIntPtr wParam, IntPtr lParam)
{
return MirandaContext.Current.CallService(MS_PROTO_CHAINRECV, wParam, lParam);
}
#endregion
}
}
@@ -0,0 +1,89 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
namespace Virtuoso.Miranda.Plugins.Infrastructure.Protocols
{
public sealed class ContactChainData
{
#region .ctors
internal unsafe ContactChainData(IntPtr pCcsData)
{
if (pCcsData == IntPtr.Zero)
throw new ArgumentNullException("pCssData");
this.ccsDataPtr = pCcsData;
CCSDATA ccsData = *(CCSDATA*)pCcsData.ToPointer();
this.contactInfo = ContactInfo.FromHandle(ccsData.ContactHandle);
this.wParam = ccsData.WParam;
this.lParam = ccsData.LParam;
this.serviceName = Translate.ToString(ccsData.ServiceNamePtr, StringEncoding.Ansi);
}
#endregion
#region Properties
private ContactInfo contactInfo;
public ContactInfo ContactInfo
{
get { return contactInfo; }
}
private string serviceName;
public string ServiceName
{
get { return serviceName; }
}
private UIntPtr wParam;
[CLSCompliant(false)]
public UIntPtr WParam
{
get { return wParam; }
}
private IntPtr lParam;
public IntPtr LParam
{
get { return lParam; }
}
private IntPtr ccsDataPtr;
internal IntPtr CcsDataPtr
{
get { return ccsDataPtr; }
}
#endregion
#region Methods
public string GetLParamAsString(StringEncoding encoding)
{
return Translate.ToString(LParam, encoding);
}
#endregion
}
}
@@ -0,0 +1,107 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using Virtuoso.Miranda.Plugins.Resources;
using System.Runtime.InteropServices;
using Virtuoso.Miranda.Plugins.Helpers;
namespace Virtuoso.Miranda.Plugins.Infrastructure.Protocols
{
public sealed class ManagedProtocol : Protocol
{
#region Constants
private const string MS_PROTO_ADDTOCONTACT = "Proto/AddToContact";
private bool Registered;
#endregion
#region .ctors
internal ManagedProtocol(string name, ProtocolType type) : base(name, type) { }
#endregion
#region Properties
private PROTOCOLDESCRIPTOR nativeDescriptor;
public PROTOCOLDESCRIPTOR NativeDescriptor
{
get { return nativeDescriptor; }
}
#endregion
#region Methods
internal void Register()
{
if (Registered)
throw new InvalidOperationException();
PROTOCOLDESCRIPTOR descriptor = new PROTOCOLDESCRIPTOR(Name, Type);
UnmanagedStructHandle<PROTOCOLDESCRIPTOR> nativeHandle = UnmanagedStructHandle<PROTOCOLDESCRIPTOR>.Empty;
try
{
nativeHandle = new UnmanagedStructHandle<PROTOCOLDESCRIPTOR>(ref descriptor);
int result = Context.CallService(MirandaServices.MS_PROTO_REGISTERMODULE, UIntPtr.Zero, nativeHandle.IntPtr);
if (result != 0)
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, result.ToString()));
this.nativeDescriptor = descriptor;
Registered = true;
}
finally
{
nativeHandle.Free();
}
}
internal void Unregister()
{
if (!Registered)
throw new InvalidOperationException();
// Currently, nothing else to do
}
public void AddToContact(ContactInfo contact)
{
if (contact == null)
throw new ArgumentNullException("contact");
AddToContact(contact.MirandaHandle);
}
public void AddToContact(IntPtr contactHandle)
{
int result = Context.CallService(MS_PROTO_ADDTOCONTACT, contactHandle, NativeDescriptor.Name);
if (result != 0)
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MS_PROTO_ADDTOCONTACT, result.ToString()));
}
#endregion
}
}
@@ -0,0 +1,322 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public enum DatabaseSettingType : byte
{
Deleted = 0, //this setting just got deleted, no other values are valid
Byte = 1, //bVal and cVal are valid
UInt16 = 2, //wVal and sVal are valid
UInt32 = 4, //dVal and lVal are valid
AsciiString = 255, //pszVal is valid
Blob = 254, //cpbVal and pbVal are valid
UTF8String = 253, //pszVal is valid
UnicodeString = 252, //pszVal is valid
}
public enum ProtocolType : int
{
Ignore = 50, // added during v0.3.3
Protocol = 1000,
Encryption = 2000,
Filter = 3000,
Translation = 4000,
Other = 10000 //avoid using this if at all possible
}
internal enum ProtocolFlagsKind : int
{
/// <summary>
/// The network capabilities that the protocol supports.
/// </summary>
Capabilities = 1,
/// <summary>
/// The status modes that the protocol supports.
/// </summary>
StatusModes = 2,
/// <summary>
/// The status modes that the protocol supports away-style messages for. Uses the <see cref="StatusModes"/> flags.
/// </summary>
AwayStatusModes = 3
}
[Flags, CLSCompliant(false)]
public enum ProtocolCapabilities : uint
{
/// <summary>
/// None.
/// </summary>
None = 0,
/// <summary>
/// Supports IM sending.
/// </summary>
IMSend = 0x00000001,
/// <summary>
/// Supports IM receiving.
/// </summary>
IMReceive = 0x00000002,
IM = (IMSend | IMReceive),
/// <summary>
/// Aupports separate URL sending.
/// </summary>
UrlSend = 0x00000004,
/// <summary>
/// Supports separate URL receiving.
/// </summary>
UrlReceive = 0x00000008,
Url = (UrlSend | UrlReceive),
/// <summary>
/// Supports file sending.
/// </summary>
FileSend = 0x00000010,
/// <summary>
/// Supports file receiving.
/// </summary>
FileReceive = 0x00000020,
File = (FileSend | FileReceive),
/// <summary>
/// Supports broadcasting away messages.
/// </summary>
ModeMessageSend = 0x00000040,
/// <summary>
/// Supports reading others' away messages.
/// </summary>
ModeMessageReceive = 0x00000080,
ModeMessage = (ModeMessageSend | ModeMessageReceive),
/// <summary>
/// Contact lists are stored on the server, not locally. See notes below.
/// </summary>
ServerContactList = 0x00000100,
/// <summary>
/// Will get authorisation requests for some or all contacts.
/// </summary>
AuthorizationRequired = 0x00000200,
/// <summary>
/// Will get 'you were added' notifications.
/// </summary>
Added = 0x00000400,
/// <summary>
/// Has an invisible list.
/// </summary>
VisibleList = 0x00000800,
/// <summary>
/// Has a visible list for when in invisible mode.
/// </summary>
InvisibleList = 0x00001000,
/// <summary>
/// Supports setting different status modes to each contact.
/// </summary>
IndividualStatus = 0x00002000,
/// <summary>
/// the protocol is extensible and Supports plugin-defined messages.
/// </summary>
Extensible = 0x00004000,
/// <summary>
/// Supports direct (not server mediated) communication between clients.
/// </summary>
P2P = 0x00008000,
/// <summary>
/// Supports creation of new user IDs.
/// </summary>
NewUser = 0x00010000,
/// <summary>
/// Has a realtime chat capability.
/// </summary>
Chat = 0x00020000,
/// <summary>
/// Supports replying to a mode message request with different text depending on the contact requesting.
/// </summary>
IndividualModeMessage = 0x00040000,
/// <summary>
/// Supports a basic user searching facility.
/// </summary>
BasicSearch = 0x00080000,
/// <summary>
/// Supports one or more protocol-specific extended search schemes.
/// </summary>
ExtendedSearch = 0x00100000,
/// <summary>
/// Supports renaming of incoming files as they are transferred.
/// </summary>
CanRenameFile = 0x00200000,
/// <summary>
/// Can resume broken file transfers.
/// </summary>
FileResume = 0x00400000,
/// <summary>
/// Can add search results to the contact list.
/// </summary>
AddSearches = 0x00800000,
/// <summary>
/// Can send contacts to other users.
/// </summary>
ContactSend = 0x01000000,
/// <summary>
/// Can receive contacts from other users.
/// </summary>
ContactReceive = 0x02000000,
Contact = (ContactSend | ContactReceive),
/// <summary>
/// Can change our user information stored on server.
/// </summary>
ChangeInfo = 0x04000000,
/// <summary>
/// Supports a search by e-mail feature.
/// </summary>
SearchByEmail = 0x08000000,
/// <summary>
/// Set if the uniquely identifying field of the network is the e-mail address.
/// </summary>
UserIDIsEmail = 0x10000000,
/// <summary>
/// Supports searching by nick/first/last names.
/// </summary>
SearchByName = 0x20000000,
/// <summary>
/// Has a dialog box to allow searching all the possible fields.
/// </summary>
ExtendedSearchUI = 0x40000000,
/// <summary>
/// The unique user IDs for this protocol are numeric.
/// </summary>
NumericUserID = 0x80000000,
}
[Flags]
public enum ProtocolStatusModes : int
{
Online = 0x00000001, //an unadorned online mode
Invisible = 0x00000002,
ShortAway = 0x00000004, //Away on ICQ, BRB on MSN
LongAway = 0x00000008, //NA on ICQ, Away on MSN
LightDND = 0x00000010, //Occupied on ICQ, Busy on MSN
HeavyDND = 0x00000020, //DND on ICQ
FreeForChat = 0x00000040,
OutToLunch = 0x00000080,
OnThePhone = 0x00000100,
Idle = 0x00000200 //added during 0.3.4 (2004/09/13)
}
public enum DatabaseEventType : short
{
Message = 0,
Url = 1,
Contacts = 2, //v0.1.2.2+
Added = 1000, //v0.1.1.0+: these used to be module-
AuthorizationRequest = 1001, //specific codes, hence the module-
File = 1002, //specific limit has been raised to 2000
}
[Flags]
public enum DatabaseEventProperties : int
{
None = 0,
First = 1, //this is the first event in the chain;
//internal only: *do not* use this flag
Sent = 2, //this event was sent by the user. If not set this
//event was received.
Read = 4, //event has been read by the user. It does not need
//to be processed any more except for history.
Rtl = 8, //event contains the right-to-left aligned text
Utf8 = 16 //event contains a text in utf-8
}
[Flags]
public enum MenuItemProperties : int
{
KeepCurrent = -1,
None = 0,
Grayed = 1,
Checked = 2,
Hidden = 4,
OnlineOnly = 8,
OfflineOnly = 16,
NotOnListOnly = 32,
NonNotOnListOnly = 64
}
[Flags]
public enum HotKeys : int
{
Alt = 0x0001,
Ctrl = 0x0002,
Shift = 0x0004,
WinKey = 0x0008
}
public enum ContactInfoPropertyType : int
{
Unknown = 0,
Byte = 1,
UInt16 = 2,
UInt32 = 3,
String = 4
}
public static class CallbackResult
{
public const int Success = 0;
public const int Failure = -1;
}
public static class EventResult
{
public const bool HonourEventChain = false;
public const bool BreakEventChain = true;
}
[Flags]
public enum ContactListEventProperties : int
{
None = 0,
/// <summary>
/// Flashes the icon even if the user is occupied, and puts the event at the top of the queue.
/// </summary>
Urgent = 1,
/// <summary>
/// The icon will not flash for ever, only a few times. This is for eg online alert.
/// </summary>
Minor = 2,
// #define CLEF_URGENT 1 //flashes the icon even if the user is occupied,
// //and puts the event at the top of the queue
//#define CLEF_ONLYAFEW 2 //the icon will not flash for ever, only a few
// //times. This is for eg online alert
//#define CLEF_UNICODE 4 //set pszTooltip as unicode
//#define CLEF_PROTOCOLGLOBAL 8 //set event globally for protocol, hContact has to be NULL,
// //lpszProtocol the protocol ID name to be set
//#if defined( _UNICODE )
// #define CLEF_TCHAR CLEF_UNICODE //will use TCHAR* instead of char*
//#else
// #define CLEF_TCHAR 0 //will return char*, as usual
//#endif
}
}
@@ -0,0 +1,33 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public abstract class RemoteObject : MarshalByRefObject
{
protected RemoteObject() { }
public override object InitializeLifetimeService()
{
return null;
}
}
}
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
internal static class RuntimeCaches
{
#region Fields
private static readonly Dictionary<string, object> Caches = new Dictionary<string, object>(1);
#endregion
#region Getters
public static IDictionary<TKey, TValue> GetCache<TKey, TValue>(string cacheName)
{
return GetCache(cacheName) as IDictionary<TKey, TValue>;
}
public static object GetCache(string name)
{
if (Caches.ContainsKey(name))
throw new ArgumentException("Cache not found.", "name");
return Caches[name];
}
public static bool CacheRegistered(string name)
{
return Caches.ContainsKey(name);
}
#endregion
#region Setters
public static void RegisterCache(string name, object cache)
{
if (Caches.ContainsKey(name))
throw new ArgumentException("Cache already registered.", "name");
Caches[name] = cache;
}
public static bool UnregisterCache(string name)
{
return Caches.Remove(name);
}
#endregion
}
}
@@ -0,0 +1,85 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Hyphen;
using System.Threading;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
/// <summary>
/// Provides information about current state of Hyphen runtime.
/// This class can be used only from the context of standalone modules (i.e. from the default AppDomain only).
/// </summary>
public static class RuntimeEnvironment
{
#region Fields
private static volatile bool Initialized;
#endregion
#region Methods
/// <summary>
/// Marks the class initialized.
/// </summary>
internal static void Initialize()
{
Initialized = true;
}
/// <summary>
/// Verifies whether the class was initialized (from the default AppDomain).
/// </summary>
/// <exception cref="NotSupportedException">Class not initialized (i.e. called from other than default AppDomain).</exception>
private static void VerifyInitialized()
{
if (!Initialized)
throw new NotSupportedException();
}
#endregion
#region Properties
private static bool hyphenIsLoading;
/// <summary>
/// Gets an indication whether the Hyphen runtime is currently loading.
/// </summary>
/// <exception cref="NotSupportedException">Class not initialized (i.e. called from other than default AppDomain).</exception>
public static bool HyphenIsLoading
{
get { VerifyInitialized(); return hyphenIsLoading; }
internal set { hyphenIsLoading = value; }
}
/// <summary>
/// Gets an indication whether the Isolated plugins are loaded.
/// </summary>
/// <exception cref="NotSupportedException">Class not initialized (i.e. called from other than default AppDomain).</exception>
public static bool IsolatedModePluginsLoaded
{
get { VerifyInitialized(); return Loader.GetInstance().PluginsLoaded; }
}
#endregion
}
}
@@ -0,0 +1,82 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public sealed class ServiceCallInterceptionManager
{
#region Fields
private readonly Dictionary<string, Callback> Interceptors;
#endregion
#region .ctors
public ServiceCallInterceptionManager()
{
this.Interceptors = new Dictionary<string, Callback>(2);
}
#endregion
#region Methods
public bool RequiresInterception(string serviceName)
{
lock (Interceptors)
return Interceptors.ContainsKey(serviceName);
}
public Callback this[string serviceName]
{
get
{
lock (Interceptors)
{
Callback interceptor = null;
Interceptors.TryGetValue(serviceName, out interceptor);
return interceptor;
}
}
set
{
Register(serviceName, value);
}
}
public void Register(string serviceName, Callback interceptor)
{
lock (Interceptors)
Interceptors[serviceName] = interceptor;
}
public void Unregister(string serviceName)
{
lock (Interceptors)
Interceptors.Remove(serviceName);
}
#endregion
}
}
@@ -0,0 +1,66 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public sealed class ServiceFunctionAttribute : HookAttribute
{
#region Fields
private string serviceName;
public string ServiceName
{
get
{
return this.serviceName;
}
set
{
this.serviceName = value;
}
}
internal override string HookName
{
get { return ServiceName; }
}
internal override HookType HookType
{
get { return HookType.ServiceFunction; }
}
#endregion
#region .ctors
public ServiceFunctionAttribute(string serviceName)
{
if (serviceName == null)
throw new ArgumentNullException("serviceName");
this.serviceName = serviceName;
}
#endregion
}
}
@@ -0,0 +1,101 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Collections;
using Virtuoso.Miranda.Plugins.Resources;
using System.Diagnostics;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public static class ServiceManager
{
[CLSCompliant(false)]
public static void CreateServiceFunction(string serviceName, Callback callback, MirandaPlugin owner)
{
if (String.IsNullOrEmpty(serviceName))
throw new ArgumentNullException("serviceName");
if (callback == null)
throw new ArgumentNullException("callback");
if (owner == null)
throw new ArgumentNullException("owner");
if (!owner.Initialized)
throw new InvalidOperationException(TextResources.ExceptionMsg_PluginNotInitialized);
HookDescriptorCollection collection = owner.Descriptor.ServiceFunctions;
try
{
SynchronizationHelper.BeginPluginUpdate(owner);
SynchronizationHelper.BeginCollectionUpdate(collection);
HookDescriptor descriptor = HookDescriptor.SetUpAndStore(collection, serviceName, owner.Descriptor, callback, HookType.ServiceFunction);
descriptor.RegisteredManually = true;
HookManager.CreateHook(descriptor);
}
finally
{
SynchronizationHelper.EndUpdate(owner);
SynchronizationHelper.EndUpdate(collection);
}
}
public static bool ServiceExists(string name)
{
return MirandaContext.Current.PluginLink.NativePluginLink.ServiceExists(name) != 0;
}
[CLSCompliant(false)]
public static Callback GetService(string serviceName)
{
return CallbackWrapper.Create(serviceName);
}
public static void RemoveServiceFunction(MirandaPlugin owner, string eventName)
{
if (owner == null)
throw new ArgumentNullException("owner");
if (String.IsNullOrEmpty(eventName))
throw new ArgumentNullException("eventName");
HookDescriptorCollection collection = owner.Descriptor.ServiceFunctions;
try
{
SynchronizationHelper.BeginCollectionUpdate(collection);
HookDescriptor descriptor = null;
if ((descriptor = collection.Find(eventName)) == null)
return;
HookManager.DestroyHook(descriptor);
collection.Remove(descriptor);
}
finally
{
SynchronizationHelper.EndUpdate(collection);
}
}
}
}
+81
View File
@@ -0,0 +1,81 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
/// <summary>
/// Manages Miranda skin entities, for example icons and sounds.
/// </summary>
/// <mHeader>m_skin.h</mHeader>
public static class Skin
{
#region Constants
private const string MS_SKIN_LOADICON = "Skin/Icons/Load",
MS_SKIN_LOADPROTOICON = "Skin/Icons/LoadProto";
#endregion
#region Icons
public static class Icons
{
public const int Message = 100;
}
#endregion
#region Methods
public static IntPtr LoadIcon(int id)
{
return (IntPtr)MirandaContext.Current.CallService(MS_SKIN_LOADICON, (UIntPtr)(uint)id, IntPtr.Zero);
}
public static IntPtr LoadProtocolIcon(StatusMode status)
{
return LoadProtocolIcon((string)null, status);
}
public static IntPtr LoadProtocolIcon(Protocol protocol, StatusMode status)
{
return LoadProtocolIcon((protocol != null ? protocol.Name : null), status);
}
public static IntPtr LoadProtocolIcon(string protocolName, StatusMode status)
{
UnmanagedStringHandle protoNamePtr = UnmanagedStringHandle.Empty;
try
{
protoNamePtr = new UnmanagedStringHandle(protocolName, StringEncoding.Ansi);
return (IntPtr)MirandaContext.Current.CallService(MS_SKIN_LOADPROTOICON, protoNamePtr.IntPtr, (IntPtr)status);
}
finally
{
protoNamePtr.Free();
}
}
#endregion
}
}
@@ -0,0 +1,46 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Helpers;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public enum StatusMode : int
{
Offline = 40071,
Online = 40072,
Away = 40073,
DND = 40074,
NA = 40075,
Occupied = 40076,
[EnumValueFriendlyName("Free for chat")]
FreeForChat = 40077,
Invisible = 40078,
[EnumValueFriendlyName("On the phone")]
OnThePhone = 40079,
[EnumValueFriendlyName("Out to lunch")]
OutToLunch = 40080,
Idle = 40081 /* do not use as a status */
}
}
@@ -0,0 +1,51 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Helpers;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
internal sealed class StringResolverCache : TypeInstanceCache<IStringResolver>
{
#region Fields
private static StringResolverCache singleton;
#endregion
#region .ctors
private StringResolverCache() { }
#endregion
#region Properties
public static StringResolverCache Singleton
{
get
{
return singleton ?? (singleton = new StringResolverCache());
}
}
#endregion
}
}
+199
View File
@@ -0,0 +1,199 @@
/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Infrastructure;
using Virtuoso.Miranda.Plugins.Resources;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Virtuoso.Miranda.Plugins.Native;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
[CLSCompliant(false)]
public static class Translate
{
#region Fields
private static readonly Type StatusEnumType = typeof(StatusMode);
#endregion
#region ToStatus
public static StatusMode ToStatus(UIntPtr wParam)
{
if (!Enum.IsDefined(StatusEnumType, (int)wParam.ToUInt32()))
throw new ArgumentException("wParam", TextResources.ExceptionMsg_InvalidValueToTranslate);
return (StatusMode)(wParam);
}
#endregion
#region ToString
public static string ToString(IntPtr lParam, StringEncoding marshalAs)
{
return ToString(lParam, 0, marshalAs, false);
}
public static string ToString(IntPtr lParam, StringEncoding marshalAs, bool transformExceptionsToNull)
{
return ToString(lParam, 0, marshalAs, transformExceptionsToNull);
}
public static string ToString(IntPtr lParam, int length, StringEncoding marshalAs)
{
return ToString(lParam, length, marshalAs, false);
}
public static string ToString(IntPtr lParam, int length, StringEncoding marshalAs, bool tranformExceptionsToNull)
{
if (lParam == IntPtr.Zero)
throw new ArgumentNullException("lParam");
if (length < 0)
throw new ArgumentOutOfRangeException("length");
if (marshalAs != StringEncoding.MirandaDefault && marshalAs != StringEncoding.Ansi && marshalAs != StringEncoding.Unicode)
throw new ArgumentOutOfRangeException("marshalAs");
try
{
reEval:
switch (marshalAs)
{
case StringEncoding.MirandaDefault:
marshalAs = MirandaEnvironment.MirandaStringEncoding;
if (marshalAs == StringEncoding.MirandaDefault) throw new ArgumentException(TextResources.ExceptionMsg_CannotDetectMirandaDefaultStringEncoding);
goto reEval;
case StringEncoding.Ansi:
if (length > 0)
return Marshal.PtrToStringAnsi(lParam, length);
else
return Marshal.PtrToStringAnsi(lParam);
case StringEncoding.Unicode:
if (length > 0)
return Marshal.PtrToStringUni(lParam, length);
else
return Marshal.PtrToStringUni(lParam);
default:
return null;
}
}
catch (Exception e)
{
if (!tranformExceptionsToNull)
throw new ArgumentException("lParam", TextResources.ExceptionMsg_InvalidValueToTranslate + e.Message, e);
else
return null;
}
}
#endregion
#region ToHandle
public static IntPtr ToHandle(UIntPtr wParam)
{
return new IntPtr((long)wParam.ToUInt64());
}
public static UIntPtr ToHandle(IntPtr lParam)
{
return new UIntPtr((ulong)lParam.ToInt64());
}
public static UnmanagedStringHandle ToHandle(string str, StringEncoding encoding)
{
return new UnmanagedStringHandle(str, encoding);
}
#endregion
#region To/From Miranda HyphenVersion Format
[CLSCompliant(false)]
public static uint ToMirandaVersion(Version version)
{
if (version == null)
throw new ArgumentNullException("version");
return (((((uint)(version.Major)) & 0xFF) << 24) | ((((uint)(version.Minor)) & 0xFF) << 16) | ((((uint)(version.Build)) & 0xFF) << 8) | (((uint)(version.MinorRevision)) & 0xFF));
}
[CLSCompliant(false)]
public static Version FromMirandaVersion(uint version)
{
return new Version((int)((version >> 24) & 0xff), (int)((version >> 16) & 0xff), (int)((version >> 8) & 0xff), (int)(version & 0xff));
}
#endregion
#region Misc.
public static byte[] ToBlob(IntPtr blobPtr, int size)
{
if (blobPtr == IntPtr.Zero)
throw new ArgumentNullException("blobPtr");
if (size < 0)
throw new ArgumentOutOfRangeException("size");
byte[] blob = new byte[size];
Marshal.Copy(blobPtr, blob, 0, size);
return blob;
}
#endregion
#region Internal helpers
internal static object ValueFromVariant(ref DBVARIANT dbVariant)
{
switch ((DbVariantValue)dbVariant.Type)
{
case DbVariantValue.DBVT_ASCIIZ:
return Translate.ToString(dbVariant.Text.TextPtr, dbVariant.Text.TextBufferSize, StringEncoding.Ansi);
case DbVariantValue.DBVT_UTF8:
return Translate.ToString(dbVariant.Text.TextPtr, dbVariant.Text.TextBufferSize, StringEncoding.Unicode);
case DbVariantValue.DBVT_BLOB:
return ToBlob(dbVariant.Blob.BlobPtr, dbVariant.Blob.Size);
case DbVariantValue.DBVT_BYTE:
return dbVariant.Primitives.Byte;
case DbVariantValue.DBVT_DELETED:
return null;
case DbVariantValue.DBVT_DWORD:
return dbVariant.Primitives.DWord;
case DbVariantValue.DBVT_WORD:
return dbVariant.Primitives.Word;
case DbVariantValue.DBVT_WCHAR:
return Marshal.PtrToStringBSTR(dbVariant.Text.TextPtr);
case DbVariantValue.DBVTF_VARIABLELENGTH:
throw new NotSupportedException();
default:
return null;
}
}
#endregion
}
}