miranda/Hyphen/Plugins/Infrastructure/Protocol.cs
2013-06-25 22:53:41 +00:00

226 lines
7.3 KiB
C#

/***********************************************************************\
* 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
}
}