diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..412eeda
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,22 @@
+# Auto detect text files and perform LF normalization
+* text=auto
+
+# Custom for Visual Studio
+*.cs diff=csharp
+*.sln merge=union
+*.csproj merge=union
+*.vbproj merge=union
+*.fsproj merge=union
+*.dbproj merge=union
+
+# Standard to msysgit
+*.doc diff=astextplain
+*.DOC diff=astextplain
+*.docx diff=astextplain
+*.DOCX diff=astextplain
+*.dot diff=astextplain
+*.DOT diff=astextplain
+*.pdf diff=astextplain
+*.PDF diff=astextplain
+*.rtf diff=astextplain
+*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ebd21a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,163 @@
+#################
+## Eclipse
+#################
+
+*.pydevproject
+.project
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.classpath
+.settings/
+.loadpath
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+
+#################
+## Visual Studio
+#################
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Rr]elease/
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.vspscc
+.builds
+*.dotCover
+
+## TODO: If you have NuGet Package Restore enabled, uncomment this
+#packages/
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+
+# Visual Studio profiler
+*.psess
+*.vsp
+
+# ReSharper is a .NET coding add-in
+_ReSharper*
+
+# Installshield output folder
+[Ee]xpress
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish
+
+# Others
+[Bb]in
+[Oo]bj
+sql
+TestResults
+*.Cache
+ClientBin
+stylecop.*
+~$*
+*.dbmdl
+Generated_Code #added for RIA/Silverlight projects
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+
+
+
+############
+## Windows
+############
+
+# Windows image file caches
+Thumbs.db
+
+# Folder config file
+Desktop.ini
+
+
+#############
+## Python
+#############
+
+*.py[co]
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+
+#Translations
+*.mo
+
+#Mr Developer
+.mr.developer.cfg
+
+# Mac crap
+.DS_Store
diff --git a/GSMComm.sln b/GSMComm.sln
new file mode 100644
index 0000000..bc3c4bc
--- /dev/null
+++ b/GSMComm.sln
@@ -0,0 +1,38 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PDUConverter", "PDUConverter\PDUConverter.csproj", "{5E657EFE-0A30-466D-B025-FF177E23A727}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GSMCommShared", "GSMCommShared\GSMCommShared.csproj", "{71EA4054-A98A-46BA-84FA-81652DB72B72}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GSMCommunication", "GSMCommunication\GSMCommunication.csproj", "{32B76F1E-B022-47C6-86EC-28639D348067}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GSMCommServer", "GSMCommServer\GSMCommServer.csproj", "{67CB92ED-436B-4005-A6D6-092503D6E496}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5E657EFE-0A30-466D-B025-FF177E23A727}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5E657EFE-0A30-466D-B025-FF177E23A727}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5E657EFE-0A30-466D-B025-FF177E23A727}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5E657EFE-0A30-466D-B025-FF177E23A727}.Release|Any CPU.Build.0 = Release|Any CPU
+ {71EA4054-A98A-46BA-84FA-81652DB72B72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {71EA4054-A98A-46BA-84FA-81652DB72B72}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {71EA4054-A98A-46BA-84FA-81652DB72B72}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {71EA4054-A98A-46BA-84FA-81652DB72B72}.Release|Any CPU.Build.0 = Release|Any CPU
+ {32B76F1E-B022-47C6-86EC-28639D348067}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {32B76F1E-B022-47C6-86EC-28639D348067}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {32B76F1E-B022-47C6-86EC-28639D348067}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {32B76F1E-B022-47C6-86EC-28639D348067}.Release|Any CPU.Build.0 = Release|Any CPU
+ {67CB92ED-436B-4005-A6D6-092503D6E496}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {67CB92ED-436B-4005-A6D6-092503D6E496}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {67CB92ED-436B-4005-A6D6-092503D6E496}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {67CB92ED-436B-4005-A6D6-092503D6E496}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/GSMCommServer/GSMCommServer.csproj b/GSMCommServer/GSMCommServer.csproj
new file mode 100644
index 0000000..a2bea1a
--- /dev/null
+++ b/GSMCommServer/GSMCommServer.csproj
@@ -0,0 +1,82 @@
+
+
+
+ {67CB92ED-436B-4005-A6D6-092503D6E496}
+ 2
+ Debug
+ AnyCPU
+ GSMCommServer
+ Library
+ GsmComm
+ v4.0
+
+
+ bin\Debug\
+ true
+ DEBUG;TRACE
+ false
+ 4
+ full
+ prompt
+ AnyCPU
+ true
+
+
+ bin\Release\
+ false
+ TRACE
+ true
+ 4
+ pdbonly
+ prompt
+ AnyCPU
+
+
+
+
+ .\GSMCommServerReferences\GSMCommShared.dll
+
+
+
+ .\GSMCommServerReferences\GSMCommunication.dll
+
+
+ .\GSMCommServerReferences\PDUConverter.dll
+
+
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+
+
\ No newline at end of file
diff --git a/GSMCommServer/GSMCommServerReferences/GSMCommShared.dll b/GSMCommServer/GSMCommServerReferences/GSMCommShared.dll
new file mode 100644
index 0000000..09feab4
Binary files /dev/null and b/GSMCommServer/GSMCommServerReferences/GSMCommShared.dll differ
diff --git a/GSMCommServer/GSMCommServerReferences/GSMCommunication.dll b/GSMCommServer/GSMCommServerReferences/GSMCommunication.dll
new file mode 100644
index 0000000..2939cc4
Binary files /dev/null and b/GSMCommServer/GSMCommServerReferences/GSMCommunication.dll differ
diff --git a/GSMCommServer/GSMCommServerReferences/PDUConverter.dll b/GSMCommServer/GSMCommServerReferences/PDUConverter.dll
new file mode 100644
index 0000000..baee9ee
Binary files /dev/null and b/GSMCommServer/GSMCommServerReferences/PDUConverter.dll differ
diff --git a/GSMCommServer/Properties/AssemblyInfo.cs b/GSMCommServer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..bba6242
--- /dev/null
+++ b/GSMCommServer/Properties/AssemblyInfo.cs
@@ -0,0 +1,17 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyCompany("Stefan Mayr")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCopyright("Copyright © 2004-2011 Stefan Mayr")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyFileVersion("1.21.0.0")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyTitle("GSMComm Server")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyVersion("1.21.0.0")]
+[assembly: CompilationRelaxations(8)]
+[assembly: ComVisible(false)]
+[assembly: Guid("51344c27-1895-4355-9289-a25D0880918f")]
+[assembly: RuntimeCompatibility(WrapNonExceptionThrows=true)]
diff --git a/GSMCommServer/Server/AuthorizationModule.cs b/GSMCommServer/Server/AuthorizationModule.cs
new file mode 100644
index 0000000..ff220a1
--- /dev/null
+++ b/GSMCommServer/Server/AuthorizationModule.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Net;
+using System.Runtime.Remoting.Channels;
+using System.Security.Principal;
+
+///
+/// Implements the authorization module for the server.
+///
+namespace GsmComm.Server
+{
+ public class AuthorizationModule : IAuthorizeRemotingConnection
+ {
+ private bool allowAnonymous;
+
+ ///
+ /// Initializes a new instance of the module.
+ ///
+ /// Specifies if users authenticated anonymously can
+ /// connect to the current channel.
+ public AuthorizationModule(bool allowAnonymous)
+ {
+ this.allowAnonymous = allowAnonymous;
+ }
+
+ ///
+ /// Gets a Boolean value that indicates whether the network address of the client is
+ /// authorized to connect on the current channel.
+ ///
+ /// The that identifies the network address of the client.
+ /// true if the network address of the client is authorized; otherwise, false.
+ public bool IsConnectingEndPointAuthorized(EndPoint endPoint)
+ {
+ return true;
+ }
+
+ ///
+ /// Gets a Boolean value that indicates whether the user identity of the client is
+ /// authorized to connect on the current channel.
+ ///
+ /// The that represents the user identity of the client.
+ /// true if the user identity of the client is authorized; otherwise, false.
+ public bool IsConnectingIdentityAuthorized(IIdentity identity)
+ {
+ bool flag = true;
+ WindowsIdentity windowsIdentity = identity as WindowsIdentity;
+ if (windowsIdentity != null && windowsIdentity.IsAnonymous && !this.allowAnonymous)
+ {
+ flag = false;
+ }
+ return flag;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommServer/Server/MessageSendErrorEventArgs.cs b/GSMCommServer/Server/MessageSendErrorEventArgs.cs
new file mode 100644
index 0000000..62a1a46
--- /dev/null
+++ b/GSMCommServer/Server/MessageSendErrorEventArgs.cs
@@ -0,0 +1,46 @@
+using System;
+
+///
+/// Provides data for the error events that deal with message sending.
+///
+namespace GsmComm.Server
+{
+ public class MessageSendErrorEventArgs : MessageSendEventArgs
+ {
+ private Exception exception;
+
+ ///
+ /// Gets the exception that caused the error.
+ ///
+ public Exception Exception
+ {
+ get
+ {
+ return this.exception;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The message that failed sending.
+ /// The destination the message was attempted to send to.
+ /// The exception that caused the error.
+ public MessageSendErrorEventArgs(string message, string destination, Exception exception) : base(message, destination)
+ {
+ this.exception = exception;
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The message that failed sending.
+ /// The destination the message was attempted to send to.
+ /// The exception that caused the error.
+ /// The name of the user from which the action started.
+ public MessageSendErrorEventArgs(string message, string destination, Exception exception, string userName) : base(message, destination, userName)
+ {
+ this.exception = exception;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommServer/Server/MessageSendErrorEventHandler.cs b/GSMCommServer/Server/MessageSendErrorEventHandler.cs
new file mode 100644
index 0000000..7763f4b
--- /dev/null
+++ b/GSMCommServer/Server/MessageSendErrorEventHandler.cs
@@ -0,0 +1,11 @@
+using System;
+
+///
+/// The method that handles the event.
+///
+/// The origin of the event.
+/// The associated with the event.
+namespace GsmComm.Server
+{
+ public delegate void MessageSendErrorEventHandler(object sender, MessageSendErrorEventArgs e);
+}
\ No newline at end of file
diff --git a/GSMCommServer/Server/MessageSendEventArgs.cs b/GSMCommServer/Server/MessageSendEventArgs.cs
new file mode 100644
index 0000000..e512328
--- /dev/null
+++ b/GSMCommServer/Server/MessageSendEventArgs.cs
@@ -0,0 +1,74 @@
+using System;
+
+///
+/// Provides data for the events that deal with message sending.
+///
+namespace GsmComm.Server
+{
+ public class MessageSendEventArgs : EventArgs
+ {
+ private string message;
+
+ private string destination;
+
+ private string userName;
+
+ ///
+ /// Gets the destination the message is being or was sent to.
+ ///
+ public string Destination
+ {
+ get
+ {
+ return this.destination;
+ }
+ }
+
+ ///
+ /// Gets the message that is being sent or was sent.
+ ///
+ public string Message
+ {
+ get
+ {
+ return this.message;
+ }
+ }
+
+ ///
+ /// Gets the user name from which the action started.
+ ///
+ public string UserName
+ {
+ get
+ {
+ return this.userName;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The message that is being sent or was sent.
+ /// The destination the message is being or was sent to.
+ public MessageSendEventArgs(string message, string destination)
+ {
+ this.message = message;
+ this.destination = destination;
+ this.userName = string.Empty;
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The message that is being sent or was sent.
+ /// The destination the message is being or was sent to.
+ /// The name of the user from which the action started.
+ public MessageSendEventArgs(string message, string destination, string userName)
+ {
+ this.message = message;
+ this.destination = destination;
+ this.userName = userName;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommServer/Server/MessageSendEventHandler.cs b/GSMCommServer/Server/MessageSendEventHandler.cs
new file mode 100644
index 0000000..15e5347
--- /dev/null
+++ b/GSMCommServer/Server/MessageSendEventHandler.cs
@@ -0,0 +1,12 @@
+using System;
+
+///
+/// The method that handles the and
+/// events.
+///
+/// The origin of the event.
+/// The associated with the event.
+namespace GsmComm.Server
+{
+ public delegate void MessageSendEventHandler(object sender, MessageSendEventArgs e);
+}
\ No newline at end of file
diff --git a/GSMCommServer/Server/SmsSender.cs b/GSMCommServer/Server/SmsSender.cs
new file mode 100644
index 0000000..289231d
--- /dev/null
+++ b/GSMCommServer/Server/SmsSender.cs
@@ -0,0 +1,193 @@
+using GsmComm.GsmCommunication;
+using GsmComm.Interfaces;
+using GsmComm.PduConverter;
+using System;
+using System.Threading;
+
+///
+/// Implements a remotable object to send SMS messages.
+///
+namespace GsmComm.Server
+{
+ public class SmsSender : MarshalByRefObject, ISmsSender
+ {
+ private GsmCommMain comm;
+
+ private bool disposed;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The COM port to connect to.
+ /// The baud rate to use.
+ /// The communictaion timeout.
+ public SmsSender(string portName, int baudRate, int timeout)
+ {
+ this.disposed = false;
+ this.comm = new GsmCommMain(portName, baudRate, timeout);
+ this.ConnectEvents();
+ try
+ {
+ this.comm.Open();
+ }
+ catch (Exception exception)
+ {
+ this.DisconnectEvents();
+ this.comm = null;
+ throw;
+ }
+ }
+
+ private void comm_MessageSendComplete(object sender, MessageEventArgs e)
+ {
+ if (this.MessageSendComplete != null)
+ {
+ string userDataText = e.Pdu.UserDataText;
+ string empty = string.Empty;
+ if (e.Pdu is SmsSubmitPdu)
+ {
+ empty = (e.Pdu as SmsSubmitPdu).DestinationAddress;
+ }
+ MessageSendEventArgs messageSendEventArg = new MessageSendEventArgs(userDataText, empty, this.GetIdentityName());
+ this.MessageSendComplete(this, messageSendEventArg);
+ }
+ }
+
+ private void comm_MessageSendFailed(object sender, MessageErrorEventArgs e)
+ {
+ if (this.MessageSendFailed != null)
+ {
+ string userDataText = e.Pdu.UserDataText;
+ string empty = string.Empty;
+ if (e.Pdu is SmsSubmitPdu)
+ {
+ empty = (e.Pdu as SmsSubmitPdu).DestinationAddress;
+ }
+ MessageSendErrorEventArgs messageSendErrorEventArg = new MessageSendErrorEventArgs(userDataText, empty, e.Exception, this.GetIdentityName());
+ this.MessageSendFailed(this, messageSendErrorEventArg);
+ }
+ }
+
+ private void comm_MessageSendStarting(object sender, MessageEventArgs e)
+ {
+ if (this.MessageSendStarting != null)
+ {
+ string userDataText = e.Pdu.UserDataText;
+ string empty = string.Empty;
+ if (e.Pdu is SmsSubmitPdu)
+ {
+ empty = (e.Pdu as SmsSubmitPdu).DestinationAddress;
+ }
+ MessageSendEventArgs messageSendEventArg = new MessageSendEventArgs(userDataText, empty, this.GetIdentityName());
+ this.MessageSendStarting(this, messageSendEventArg);
+ }
+ }
+
+ private void ConnectEvents()
+ {
+ this.comm.MessageSendStarting += new GsmCommMain.MessageEventHandler(this.comm_MessageSendStarting);
+ this.comm.MessageSendComplete += new GsmCommMain.MessageEventHandler(this.comm_MessageSendComplete);
+ this.comm.MessageSendFailed += new GsmCommMain.MessageErrorEventHandler(this.comm_MessageSendFailed);
+ }
+
+ private void DisconnectEvents()
+ {
+ this.comm.MessageSendStarting -= new GsmCommMain.MessageEventHandler(this.comm_MessageSendStarting);
+ this.comm.MessageSendComplete -= new GsmCommMain.MessageEventHandler(this.comm_MessageSendComplete);
+ this.comm.MessageSendFailed -= new GsmCommMain.MessageErrorEventHandler(this.comm_MessageSendFailed);
+ }
+
+ private string GetIdentityName()
+ {
+ return Thread.CurrentPrincipal.Identity.Name;
+ }
+
+ ///
+ /// Determines how long the remoting object lives.
+ ///
+ /// Always null so that the object lives forever.
+ public override object InitializeLifetimeService()
+ {
+ return null;
+ }
+
+ ///
+ /// Sends an SMS message.
+ ///
+ /// The message to send.
+ /// The destination (phone number) to which the message should be sent.
+ public void SendMessage(string message, string destination)
+ {
+ lock (this)
+ {
+ if (!this.disposed)
+ {
+ SmsSubmitPdu smsSubmitPdu = new SmsSubmitPdu(message, destination);
+ this.comm.SendMessage(smsSubmitPdu);
+ }
+ else
+ {
+ throw new ObjectDisposedException("SmsSender");
+ }
+ }
+ }
+
+ ///
+ /// Sends an SMS message.
+ ///
+ /// The message to send.
+ /// The destination (phone number) to which the message should be sent.
+ /// Specifies if the message should be sent as Unicode.
+ public void SendMessage(string message, string destination, bool unicode)
+ {
+ SmsSubmitPdu smsSubmitPdu;
+ lock (this)
+ {
+ if (!this.disposed)
+ {
+ if (!unicode)
+ {
+ smsSubmitPdu = new SmsSubmitPdu(message, destination);
+ }
+ else
+ {
+ smsSubmitPdu = new SmsSubmitPdu(message, destination, 8);
+ }
+ this.comm.SendMessage(smsSubmitPdu);
+ }
+ else
+ {
+ throw new ObjectDisposedException("SmsSender");
+ }
+ }
+ }
+
+ ///
+ /// Stops the SMS sender and releases its resources.
+ ///
+ public void Shutdown()
+ {
+ if (!this.disposed)
+ {
+ this.comm.Close();
+ this.DisconnectEvents();
+ this.disposed = true;
+ }
+ }
+
+ ///
+ /// The event that occurs after a successful message transfer.
+ ///
+ public event MessageSendEventHandler MessageSendComplete;
+
+ ///
+ /// The event that occurs after a failed message transfer.
+ ///
+ public event MessageSendErrorEventHandler MessageSendFailed;
+
+ ///
+ /// The event that occurs immediately before transferring a new message.
+ ///
+ public event MessageSendEventHandler MessageSendStarting;
+ }
+}
\ No newline at end of file
diff --git a/GSMCommServer/Server/SmsServer.cs b/GSMCommServer/Server/SmsServer.cs
new file mode 100644
index 0000000..a85a158
--- /dev/null
+++ b/GSMCommServer/Server/SmsServer.cs
@@ -0,0 +1,360 @@
+using System;
+using System.Collections;
+using System.Runtime.Remoting;
+using System.Runtime.Remoting.Channels;
+using System.Runtime.Remoting.Channels.Tcp;
+
+///
+/// Implements a server for sending SMS messages remotely.
+///
+///
+/// The server uses .NET remoting with a TCP channel to publish an object.
+/// After starting, the server can be accessed by default at tcp://(servername):2000/SMSSender.
+///
+namespace GsmComm.Server
+{
+ public class SmsServer : IDisposable
+ {
+ private SmsSender smsSender;
+
+ private IChannel channel;
+
+ private ObjRef objRefSmsSender;
+
+ private int networkPort;
+
+ private string uri;
+
+ private bool isSecured;
+
+ private AuthorizationModule authModule;
+
+ private bool allowAnonymous;
+
+ private string portName;
+
+ private int baudRate;
+
+ private int timeout;
+
+ ///
+ /// Gets or sets whether anonymous users can connect when the server is secured.
+ ///
+ /// If this property is changed, while the server is running, the server must be restarted.
+ public bool AllowAnonymous
+ {
+ get
+ {
+ return this.allowAnonymous;
+ }
+ set
+ {
+ this.allowAnonymous = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the baud rate to use when communicating with the phone.
+ ///
+ /// If this property is changed, while the server is running, the server must be restarted.
+ public int BaudRate
+ {
+ get
+ {
+ return this.baudRate;
+ }
+ set
+ {
+ this.baudRate = value;
+ }
+ }
+
+ ///
+ /// Gets or sets a value that indicates whether security is enabled for the server.
+ ///
+ ///
+ /// When security is enabled, only user identities authenticated by Windows are allowed to
+ /// connect to the server and the communication between server and client is encrypted.
+ /// Clients must also have security enabled to be able to connect to the server.
+ /// Additionally, access may be allowed or denied for specific users when in secure mode.
+ /// This is currently determined by the property that specifies whether
+ /// anonymous users can connect or not.
+ /// If this property is changed, while the server is running, the server must be restarted.
+ ///
+ public bool IsSecured
+ {
+ get
+ {
+ return this.isSecured;
+ }
+ set
+ {
+ this.isSecured = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the network port for the SMS server to listen for requests.
+ ///
+ /// If this property is changed, while the server is running, the server must be restarted.
+ public int NetworkPort
+ {
+ get
+ {
+ return this.networkPort;
+ }
+ set
+ {
+ this.networkPort = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the COM port where the phone is connected.
+ ///
+ /// If this property is changed, while the server is running, the server must be restarted.
+ public string PortName
+ {
+ get
+ {
+ return this.portName;
+ }
+ set
+ {
+ this.portName = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the timeout when communicating with the phone.
+ ///
+ /// If this property is changed, while the server is running, the server must be restarted.
+ public int Timeout
+ {
+ get
+ {
+ return this.timeout;
+ }
+ set
+ {
+ this.timeout = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the URI under which the SMS sender is available.
+ ///
+ /// If this property is changed, while the server is running, the server must be restarted.
+ public string Uri
+ {
+ get
+ {
+ return this.uri;
+ }
+ set
+ {
+ this.uri = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SmsServer()
+ {
+ this.smsSender = null;
+ this.channel = null;
+ this.objRefSmsSender = null;
+ this.networkPort = 2000;
+ this.uri = "SMSSender";
+ this.isSecured = false;
+ this.authModule = null;
+ this.allowAnonymous = false;
+ this.portName = "COM1";
+ this.baudRate = 19200;
+ this.timeout = 300;
+ }
+
+ private void ConnectEvents()
+ {
+ this.smsSender.MessageSendStarting += new MessageSendEventHandler(this.smsSender_MessageSendStarting);
+ this.smsSender.MessageSendComplete += new MessageSendEventHandler(this.smsSender_MessageSendComplete);
+ this.smsSender.MessageSendFailed += new MessageSendErrorEventHandler(this.smsSender_MessageSendFailed);
+ }
+
+ private void DisconnectEvents()
+ {
+ this.smsSender.MessageSendStarting -= new MessageSendEventHandler(this.smsSender_MessageSendStarting);
+ this.smsSender.MessageSendComplete -= new MessageSendEventHandler(this.smsSender_MessageSendComplete);
+ this.smsSender.MessageSendFailed -= new MessageSendErrorEventHandler(this.smsSender_MessageSendFailed);
+ }
+
+ ///
+ /// Disposes of the host.
+ ///
+ public void Dispose()
+ {
+ this.StopInternal();
+ }
+
+ ///
+ /// Finalizes the class.
+ ///
+ protected override void Finalize()
+ {
+ try
+ {
+ this.Dispose();
+ }
+ finally
+ {
+ this.Finalize();
+ }
+ }
+
+ ///
+ /// Tells if the remoting server is currently running.
+ ///
+ /// true if the server is running, false otherwise.
+ public bool IsRunning()
+ {
+ return this.smsSender != null;
+ }
+
+ private void smsSender_MessageSendComplete(object sender, MessageSendEventArgs e)
+ {
+ if (this.MessageSendComplete != null)
+ {
+ this.MessageSendComplete(this, e);
+ }
+ }
+
+ private void smsSender_MessageSendFailed(object sender, MessageSendErrorEventArgs e)
+ {
+ if (this.MessageSendFailed != null)
+ {
+ this.MessageSendFailed(this, e);
+ }
+ }
+
+ private void smsSender_MessageSendStarting(object sender, MessageSendEventArgs e)
+ {
+ if (this.MessageSendStarting != null)
+ {
+ this.MessageSendStarting(this, e);
+ }
+ }
+
+ ///
+ /// Starts the server.
+ ///
+ /// Server is already running.
+ public void Start()
+ {
+ if (this.smsSender == null)
+ {
+ IDictionary hashtables = new Hashtable();
+ hashtables["port"] = this.networkPort;
+ hashtables["name"] = string.Concat("SMSSenderTCPChannel", this.networkPort.ToString());
+ if (this.isSecured)
+ {
+ hashtables["secure"] = "true";
+ this.authModule = new AuthorizationModule(this.allowAnonymous);
+ }
+ TcpServerChannel tcpServerChannel = new TcpServerChannel(hashtables, null, this.authModule);
+ SmsSender smsSender = null;
+ ObjRef objRef = null;
+ try
+ {
+ ChannelServices.RegisterChannel(tcpServerChannel, this.isSecured);
+ try
+ {
+ smsSender = new SmsSender(this.portName, this.baudRate, this.timeout);
+ objRef = RemotingServices.Marshal(smsSender, this.uri);
+ }
+ catch (Exception exception)
+ {
+ ChannelServices.UnregisterChannel(tcpServerChannel);
+ throw;
+ }
+ }
+ catch (Exception exception1)
+ {
+ tcpServerChannel.StopListening(null);
+ throw;
+ }
+ this.channel = tcpServerChannel;
+ this.smsSender = smsSender;
+ this.objRefSmsSender = objRef;
+ this.ConnectEvents();
+ return;
+ }
+ else
+ {
+ throw new InvalidOperationException("Server is already running.");
+ }
+ }
+
+ ///
+ /// Stops the server.
+ ///
+ /// Server is not running.
+ public void Stop()
+ {
+ if (this.smsSender != null)
+ {
+ this.StopInternal();
+ return;
+ }
+ else
+ {
+ throw new InvalidOperationException("Server is not running.");
+ }
+ }
+
+ private void StopInternal()
+ {
+ if (this.smsSender != null)
+ {
+ try
+ {
+ RemotingServices.Disconnect(this.smsSender);
+ this.smsSender.Shutdown();
+ this.DisconnectEvents();
+ }
+ finally
+ {
+ this.objRefSmsSender = null;
+ this.smsSender = null;
+ }
+ }
+ if (this.channel != null)
+ {
+ try
+ {
+ ChannelServices.UnregisterChannel(this.channel);
+ }
+ finally
+ {
+ this.channel = null;
+ this.authModule = null;
+ }
+ }
+ }
+
+ ///
+ /// The event that occurs after a successful message transfer.
+ ///
+ public event MessageSendEventHandler MessageSendComplete;
+
+ ///
+ /// The event that occurs after a failed message transfer.
+ ///
+ public event MessageSendErrorEventHandler MessageSendFailed;
+
+ ///
+ /// The event that occurs immediately before transferring a new message.
+ ///
+ public event MessageSendEventHandler MessageSendStarting;
+ }
+}
\ No newline at end of file
diff --git a/GSMCommShared/CommException.cs b/GSMCommShared/CommException.cs
new file mode 100644
index 0000000..f9835d7
--- /dev/null
+++ b/GSMCommShared/CommException.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Runtime.Serialization;
+
+///
+/// General exception that gets thrown upon a communication error with the device.
+///
+namespace GsmComm.GsmCommunication
+{
+ [Serializable]
+ public class CommException : ApplicationException
+ {
+ private string commTrace;
+
+ ///
+ /// Gets the communication trace associated with the exception.
+ ///
+ public string CommTrace
+ {
+ get
+ {
+ return this.commTrace;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A message that describes the error.
+ public CommException(string message) : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message and a communication trace.
+ ///
+ /// A message that describes the error.
+ /// The communication that occurred right before the error.
+ public CommException(string message, string commTrace) : base(message)
+ {
+ this.commTrace = commTrace;
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// A message that describes the error.
+ /// The exception that is the cause of the current exception.
+ public CommException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message, a communication trace and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// A message that describes the error.
+ /// The communication that occurred right before the error.
+ /// The exception that is the cause of the current exception.
+ public CommException(string message, string commTrace, Exception innerException) : base(message, innerException)
+ {
+ this.commTrace = commTrace;
+ }
+
+ ///
+ /// Initializes a new instance of the class with serialized data.
+ ///
+ /// The object that holds the serialized object data.
+ /// The contextual information about the source or destination.
+ protected CommException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommShared/GSMCommShared.csproj b/GSMCommShared/GSMCommShared.csproj
new file mode 100644
index 0000000..4ef338f
--- /dev/null
+++ b/GSMCommShared/GSMCommShared.csproj
@@ -0,0 +1,57 @@
+
+
+
+ {71ea4054-a98a-46ba-84fa-81652db72b72}
+ 2
+ Debug
+ AnyCPU
+ GSMCommShared
+ Library
+ GsmComm
+ v4.0
+
+
+ bin\Debug\
+ true
+ DEBUG;TRACE
+ false
+ 4
+ full
+ prompt
+ AnyCPU
+
+
+ bin\Release\
+ false
+ TRACE
+ true
+ 4
+ pdbonly
+ prompt
+ AnyCPU
+
+
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+
+
\ No newline at end of file
diff --git a/GSMCommShared/GsmCommunication/CommException.cs b/GSMCommShared/GsmCommunication/CommException.cs
new file mode 100644
index 0000000..f9835d7
--- /dev/null
+++ b/GSMCommShared/GsmCommunication/CommException.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Runtime.Serialization;
+
+///
+/// General exception that gets thrown upon a communication error with the device.
+///
+namespace GsmComm.GsmCommunication
+{
+ [Serializable]
+ public class CommException : ApplicationException
+ {
+ private string commTrace;
+
+ ///
+ /// Gets the communication trace associated with the exception.
+ ///
+ public string CommTrace
+ {
+ get
+ {
+ return this.commTrace;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A message that describes the error.
+ public CommException(string message) : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message and a communication trace.
+ ///
+ /// A message that describes the error.
+ /// The communication that occurred right before the error.
+ public CommException(string message, string commTrace) : base(message)
+ {
+ this.commTrace = commTrace;
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// A message that describes the error.
+ /// The exception that is the cause of the current exception.
+ public CommException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message, a communication trace and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// A message that describes the error.
+ /// The communication that occurred right before the error.
+ /// The exception that is the cause of the current exception.
+ public CommException(string message, string commTrace, Exception innerException) : base(message, innerException)
+ {
+ this.commTrace = commTrace;
+ }
+
+ ///
+ /// Initializes a new instance of the class with serialized data.
+ ///
+ /// The object that holds the serialized object data.
+ /// The contextual information about the source or destination.
+ protected CommException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommShared/GsmCommunication/MessageServiceErrorException.cs b/GSMCommShared/GsmCommunication/MessageServiceErrorException.cs
new file mode 100644
index 0000000..203cb47
--- /dev/null
+++ b/GSMCommShared/GsmCommunication/MessageServiceErrorException.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Runtime.Serialization;
+
+///
+/// The exception that gets thrown when there is an error with the message service.
+///
+namespace GsmComm.GsmCommunication
+{
+ [Serializable]
+ public class MessageServiceErrorException : CommException
+ {
+ private int errorCode;
+
+ ///
+ /// Gets the error code reported by the network.
+ ///
+ public int ErrorCode
+ {
+ get
+ {
+ return this.errorCode;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message, an error code and a communication trace.
+ ///
+ /// A message that describes the error.
+ /// The error code reported by the network.
+ /// The communication that occurred right before the error.
+ /// This exception gets thrown when an action can not be executed due to a message service error.
+ public MessageServiceErrorException(string message, int errorCode, string commTrace) : base(message, commTrace)
+ {
+ this.errorCode = errorCode;
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message, an error code, a communication trace and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// A message that describes the error.
+ /// The error code reported by the network.
+ /// The communication that occurred right before the error.
+ /// The exception that is the cause of the current exception.
+ /// This exception gets thrown when an action can not be executed due to a message service error.
+ public MessageServiceErrorException(string message, int errorCode, string commTrace, Exception innerException) : base(message, commTrace, innerException)
+ {
+ this.errorCode = errorCode;
+ }
+
+ ///
+ /// Initializes a new instance of the class with serialized data.
+ ///
+ /// The object that holds the serialized object data.
+ /// The contextual information about the source or destination.
+ protected MessageServiceErrorException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommShared/GsmCommunication/MobileEquipmentErrorException.cs b/GSMCommShared/GsmCommunication/MobileEquipmentErrorException.cs
new file mode 100644
index 0000000..c9e0614
--- /dev/null
+++ b/GSMCommShared/GsmCommunication/MobileEquipmentErrorException.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Runtime.Serialization;
+
+///
+/// The exception that gets thrown when the device detects an internal error.
+///
+namespace GsmComm.GsmCommunication
+{
+ [Serializable]
+ public class MobileEquipmentErrorException : CommException
+ {
+ private int errorCode;
+
+ ///
+ /// Gets the error code reported by the device.
+ ///
+ public int ErrorCode
+ {
+ get
+ {
+ return this.errorCode;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message, an error code and a communication trace.
+ ///
+ /// A message that describes the error.
+ /// The error code reported by the device.
+ /// The communication that occurred right before the error.
+ /// This exception gets thrown when an action can not be executed due to an internal device error.
+ public MobileEquipmentErrorException(string message, int errorCode, string commTrace) : base(message, commTrace)
+ {
+ this.errorCode = errorCode;
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message, an error code, a communication trace and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// A message that describes the error.
+ /// The error code reported by the device.
+ /// The communication that occurred right before the error.
+ /// The exception that is the cause of the current exception.
+ /// This exception gets thrown when an action can not be executed due to an internal device error.
+ public MobileEquipmentErrorException(string message, int errorCode, string commTrace, Exception innerException) : base(message, commTrace, innerException)
+ {
+ this.errorCode = errorCode;
+ }
+
+ ///
+ /// Initializes a new instance of the class with serialized data.
+ ///
+ /// The object that holds the serialized object data.
+ /// The contextual information about the source or destination.
+ protected MobileEquipmentErrorException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommShared/Interfaces/ISmsSender.cs b/GSMCommShared/Interfaces/ISmsSender.cs
new file mode 100644
index 0000000..338d0c4
--- /dev/null
+++ b/GSMCommShared/Interfaces/ISmsSender.cs
@@ -0,0 +1,25 @@
+using System;
+
+///
+/// Defines the interface for an SMS Sender.
+///
+namespace GsmComm.Interfaces
+{
+ public interface ISmsSender
+ {
+ ///
+ /// Sends an SMS message.
+ ///
+ /// The message to send.
+ /// The destination (phone number) to which the message should be sent.
+ void SendMessage(string message, string destination);
+
+ ///
+ /// Sends an SMS message.
+ ///
+ /// The message to send.
+ /// The destination (phone number) to which the message should be sent.
+ /// Specifies if the message should be sent as Unicode.
+ void SendMessage(string message, string destination, bool unicode);
+ }
+}
\ No newline at end of file
diff --git a/GSMCommShared/MessageServiceErrorException.cs b/GSMCommShared/MessageServiceErrorException.cs
new file mode 100644
index 0000000..203cb47
--- /dev/null
+++ b/GSMCommShared/MessageServiceErrorException.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Runtime.Serialization;
+
+///
+/// The exception that gets thrown when there is an error with the message service.
+///
+namespace GsmComm.GsmCommunication
+{
+ [Serializable]
+ public class MessageServiceErrorException : CommException
+ {
+ private int errorCode;
+
+ ///
+ /// Gets the error code reported by the network.
+ ///
+ public int ErrorCode
+ {
+ get
+ {
+ return this.errorCode;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message, an error code and a communication trace.
+ ///
+ /// A message that describes the error.
+ /// The error code reported by the network.
+ /// The communication that occurred right before the error.
+ /// This exception gets thrown when an action can not be executed due to a message service error.
+ public MessageServiceErrorException(string message, int errorCode, string commTrace) : base(message, commTrace)
+ {
+ this.errorCode = errorCode;
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message, an error code, a communication trace and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// A message that describes the error.
+ /// The error code reported by the network.
+ /// The communication that occurred right before the error.
+ /// The exception that is the cause of the current exception.
+ /// This exception gets thrown when an action can not be executed due to a message service error.
+ public MessageServiceErrorException(string message, int errorCode, string commTrace, Exception innerException) : base(message, commTrace, innerException)
+ {
+ this.errorCode = errorCode;
+ }
+
+ ///
+ /// Initializes a new instance of the class with serialized data.
+ ///
+ /// The object that holds the serialized object data.
+ /// The contextual information about the source or destination.
+ protected MessageServiceErrorException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommShared/MobileEquipmentErrorException.cs b/GSMCommShared/MobileEquipmentErrorException.cs
new file mode 100644
index 0000000..c9e0614
--- /dev/null
+++ b/GSMCommShared/MobileEquipmentErrorException.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Runtime.Serialization;
+
+///
+/// The exception that gets thrown when the device detects an internal error.
+///
+namespace GsmComm.GsmCommunication
+{
+ [Serializable]
+ public class MobileEquipmentErrorException : CommException
+ {
+ private int errorCode;
+
+ ///
+ /// Gets the error code reported by the device.
+ ///
+ public int ErrorCode
+ {
+ get
+ {
+ return this.errorCode;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message, an error code and a communication trace.
+ ///
+ /// A message that describes the error.
+ /// The error code reported by the device.
+ /// The communication that occurred right before the error.
+ /// This exception gets thrown when an action can not be executed due to an internal device error.
+ public MobileEquipmentErrorException(string message, int errorCode, string commTrace) : base(message, commTrace)
+ {
+ this.errorCode = errorCode;
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error
+ /// message, an error code, a communication trace and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// A message that describes the error.
+ /// The error code reported by the device.
+ /// The communication that occurred right before the error.
+ /// The exception that is the cause of the current exception.
+ /// This exception gets thrown when an action can not be executed due to an internal device error.
+ public MobileEquipmentErrorException(string message, int errorCode, string commTrace, Exception innerException) : base(message, commTrace, innerException)
+ {
+ this.errorCode = errorCode;
+ }
+
+ ///
+ /// Initializes a new instance of the class with serialized data.
+ ///
+ /// The object that holds the serialized object data.
+ /// The contextual information about the source or destination.
+ protected MobileEquipmentErrorException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommShared/Properties/AssemblyInfo.cs b/GSMCommShared/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..543a3bf
--- /dev/null
+++ b/GSMCommShared/Properties/AssemblyInfo.cs
@@ -0,0 +1,17 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyCompany("Stefan Mayr")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCopyright("Copyright © 2004-2011 Stefan Mayr")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyFileVersion("1.21.0.0")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyTitle("GSMComm Shared Implementations")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyVersion("1.21.0.0")]
+[assembly: CompilationRelaxations(8)]
+[assembly: ComVisible(false)]
+[assembly: Guid("c43ba0b1-3ffa-4b02-8fbd-2d5997e9b5c5")]
+[assembly: RuntimeCompatibility(WrapNonExceptionThrows=true)]
diff --git a/GSMCommunication/GSMCommunication.csproj b/GSMCommunication/GSMCommunication.csproj
new file mode 100644
index 0000000..e7d0d86
--- /dev/null
+++ b/GSMCommunication/GSMCommunication.csproj
@@ -0,0 +1,250 @@
+
+
+
+ {32b76f1e-b022-47c6-86ec-28639d348067}
+ 2
+ Debug
+ AnyCPU
+ GSMCommunication
+ Library
+ GsmComm
+ v4.0
+
+
+ bin\Debug\
+ true
+ DEBUG;TRACE
+ false
+ 4
+ full
+ prompt
+ AnyCPU
+
+
+ bin\Release\
+ false
+ TRACE
+ true
+ 4
+ pdbonly
+ prompt
+ AnyCPU
+
+
+
+ .\GSMCommunicationReferences\PDUConverter.dll
+
+
+
+ .\GSMCommunicationReferences\GSMCommShared.dll
+
+
+
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+
+
\ No newline at end of file
diff --git a/GSMCommunication/GSMCommunicationReferences/GSMCommShared.dll b/GSMCommunication/GSMCommunicationReferences/GSMCommShared.dll
new file mode 100644
index 0000000..09feab4
Binary files /dev/null and b/GSMCommunication/GSMCommunicationReferences/GSMCommShared.dll differ
diff --git a/GSMCommunication/GSMCommunicationReferences/PDUConverter.dll b/GSMCommunication/GSMCommunicationReferences/PDUConverter.dll
new file mode 100644
index 0000000..baee9ee
Binary files /dev/null and b/GSMCommunication/GSMCommunicationReferences/PDUConverter.dll differ
diff --git a/GSMCommunication/GsmCommunication/AddressData.cs b/GSMCommunication/GsmCommunication/AddressData.cs
new file mode 100644
index 0000000..a815098
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/AddressData.cs
@@ -0,0 +1,47 @@
+using System;
+
+///
+/// Contains network address data.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class AddressData
+ {
+ private string address;
+
+ private int typeOfAddress;
+
+ ///
+ /// Gets the network address.
+ ///
+ public string Address
+ {
+ get
+ {
+ return this.address;
+ }
+ }
+
+ ///
+ /// Gets the type of the .
+ ///
+ public int TypeOfAddress
+ {
+ get
+ {
+ return this.typeOfAddress;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The network address
+ /// The type of the given address
+ public AddressData(string address, int typeOfAddress)
+ {
+ this.address = address;
+ this.typeOfAddress = typeOfAddress;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/BatteryChargeInfo.cs b/GSMCommunication/GsmCommunication/BatteryChargeInfo.cs
new file mode 100644
index 0000000..eb460c1
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/BatteryChargeInfo.cs
@@ -0,0 +1,53 @@
+using System;
+
+///
+/// Contains the ME battery charging status and charge level.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class BatteryChargeInfo
+ {
+ private int bcs;
+
+ private int bcl;
+
+ ///
+ /// Gets the battery charge level.
+ ///
+ /// Usual values are in the range from 0 (empty) to 100 (full).
+ public int BatteryChargeLevel
+ {
+ get
+ {
+ return this.bcl;
+ }
+ }
+
+ ///
+ /// Gets the battery charging status.
+ ///
+ /// Usual values are 0 for "not charging" and 1 for "charging".
+ public int BatteryChargingStatus
+ {
+ get
+ {
+ return this.bcs;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The battery charging status, usually 0 for "not charging" and 1 for "charging".
+ ///
+ ///
+ /// The battery charge level, usually in the range of 0 (empty) to 100 (full).
+ ///
+ public BatteryChargeInfo(int batteryChargingStatus, int batteryChargeLevel)
+ {
+ this.bcs = batteryChargingStatus;
+ this.bcl = batteryChargeLevel;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/CbmIndicationStyle.cs b/GSMCommunication/GsmCommunication/CbmIndicationStyle.cs
new file mode 100644
index 0000000..cea16f3
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/CbmIndicationStyle.cs
@@ -0,0 +1,30 @@
+///
+/// Specifies the possible indication settings for new cell broadcast messages (CBMs).
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum CbmIndicationStyle
+ {
+ ///
+ /// No CBM indications are routed to the TE.
+ ///
+ Disabled,
+ ///
+ /// If CBM is stored into ME/TA, indication of the memory location is routed to the TE.
+ ///
+ RouteMemoryLocation,
+ ///
+ /// New CBMs are routed directly to the TE.
+ ///
+ /// If ME supports data coding groups which define special routing also for messages other than
+ /// class 3 (e.g. SIM specific messages), ME may choose not to route messages of such data coding schemes
+ /// into TE (indication of a stored CBM may be given as with .
+ RouteMessage,
+ ///
+ /// Class 3 CBMs are routed directly to TE using the same indications as with .
+ /// If CBM storage is supported, messages of other classes result in indication as with
+ /// .
+ ///
+ RouteSpecial
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/Charset.cs b/GSMCommunication/GsmCommunication/Charset.cs
new file mode 100644
index 0000000..4b4c8d8
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/Charset.cs
@@ -0,0 +1,35 @@
+using System;
+
+///
+/// Lists some common character sets.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class Charset
+ {
+ /// The UCS2 (Unicode) character set
+ public const string Ucs2 = "UCS2";
+
+ /// The GSM character set
+ public const string Gsm = "GSM";
+
+ /// The PCCP437 character set
+ public const string Pccp437 = "PCCP437";
+
+ /// The PCDN character set
+ public const string Pcdn = "PCDN";
+
+ /// The IRA character set
+ public const string Ira = "IRA";
+
+ /// The ISO 8859-1 character set
+ public const string Iso8859_1 = "8859-1";
+
+ /// The characters encoded as hex
+ public const string Hex = "HEX";
+
+ public Charset()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/DecodedShortMessage.cs b/GSMCommunication/GsmCommunication/DecodedShortMessage.cs
new file mode 100644
index 0000000..515147e
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/DecodedShortMessage.cs
@@ -0,0 +1,78 @@
+using GsmComm.PduConverter;
+using System;
+
+///
+/// Represents a short message from the phone in its decoded state.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class DecodedShortMessage
+ {
+ private int index;
+
+ private SmsPdu data;
+
+ private PhoneMessageStatus status;
+
+ private string storage;
+
+ ///
+ /// Gets the decoded message.
+ ///
+ public SmsPdu Data
+ {
+ get
+ {
+ return this.data;
+ }
+ }
+
+ ///
+ /// Gets the index where the message is saved in the device in the .
+ ///
+ public int Index
+ {
+ get
+ {
+ return this.index;
+ }
+ }
+
+ ///
+ /// Gets the parsed message status.
+ ///
+ public PhoneMessageStatus Status
+ {
+ get
+ {
+ return this.status;
+ }
+ }
+
+ ///
+ /// Gets the phone storage the message was read from.
+ ///
+ public string Storage
+ {
+ get
+ {
+ return this.storage;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The index where the message is saved in the device in the .
+ /// The decoded message.
+ /// The parsed message status.
+ /// The phone storage the message was read from.
+ public DecodedShortMessage(int index, SmsPdu data, PhoneMessageStatus status, string storage)
+ {
+ this.index = index;
+ this.data = data;
+ this.status = status;
+ this.storage = storage;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/DeleteFlag.cs b/GSMCommunication/GsmCommunication/DeleteFlag.cs
new file mode 100644
index 0000000..cb8a54e
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/DeleteFlag.cs
@@ -0,0 +1,30 @@
+///
+/// Lists the possible delete flags for AT+CMGD.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum DeleteFlag
+ {
+ /// Delete the message specified in index.
+ DeleteSpecified,
+ ///
+ /// Delete all read messages from preferred message storage, leaving unread messages and stored mobile
+ /// originated messages (whether sent or not) untouched.
+ ///
+ DeleteRead,
+ ///
+ /// Delete all read messages from preferred message storage and sent mobile originated messages,
+ /// leaving unread messages and unsent mobile originated messages untouched.
+ ///
+ DeleteReadAndSent,
+ ///
+ /// Delete all read messages from preferred message storage, sent and unsent mobile originated messages
+ /// leaving unread messages untouched.
+ ///
+ DeleteReadSentAndUnsent,
+ ///
+ /// Delete all messages from preferred message storage including unread messages.
+ ///
+ DeleteAll
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/DeleteScope.cs b/GSMCommunication/GsmCommunication/DeleteScope.cs
new file mode 100644
index 0000000..190a92e
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/DeleteScope.cs
@@ -0,0 +1,17 @@
+///
+/// Lists the possible scopes for deleting short messages.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum DeleteScope
+ {
+ /// Delete all read messages.
+ Read = 1,
+ /// Delete all read and sent messages.
+ ReadAndSent = 2,
+ /// Delete all read, sent and unsent messages
+ ReadSentAndUnsent = 3,
+ /// Delete all messages including unread messages.
+ All = 4
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/GsmCommMain.cs b/GSMCommunication/GsmCommunication/GsmCommMain.cs
new file mode 100644
index 0000000..e198f8e
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/GsmCommMain.cs
@@ -0,0 +1,1543 @@
+using GsmComm.PduConverter;
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Runtime.Remoting.Messaging;
+
+///
+/// Interacts with a mobile phone to execute various functions.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class GsmCommMain
+ {
+ ///
+ /// The default port to connect to.
+ ///
+ public const string DefaultPortName = "COM1";
+
+ ///
+ /// The default baud rate to use.
+ ///
+ public const int DefaultBaudRate = 19200;
+
+ ///
+ /// The default communication timeout.
+ ///
+ public const int DefaultTimeout = 300;
+
+ private GsmPhone theDevice;
+
+ private static bool versionInfoLogged;
+
+ private LogLevel logLevel;
+
+ ///
+ /// Gets the baud rate in use.
+ ///
+ public int BaudRate
+ {
+ get
+ {
+ return this.theDevice.BaudRate;
+ }
+ }
+
+ ///
+ /// Gets or sets the delay in milliseconds between the checks to verify that the connection
+ /// to the phone is still alive.
+ ///
+ public int ConnectionCheckDelay
+ {
+ get
+ {
+ return this.theDevice.ConnectionCheckDelay;
+ }
+ set
+ {
+ this.theDevice.ConnectionCheckDelay = value;
+ }
+ }
+
+ ///
+ /// Get or sets the current log level for this instance.
+ ///
+ public LogLevel LogLevel
+ {
+ get
+ {
+ return this.logLevel;
+ }
+ set
+ {
+ this.logLevel = value;
+ this.theDevice.LogLevel = value;
+ }
+ }
+
+ ///
+ /// Gets COM port currently connected to.
+ ///
+ public string PortName
+ {
+ get
+ {
+ return this.theDevice.PortName;
+ }
+ }
+
+ ///
+ /// Gets the current communication timeout.
+ ///
+ public int Timeout
+ {
+ get
+ {
+ return this.theDevice.Timeout;
+ }
+ }
+
+ static GsmCommMain()
+ {
+ GsmCommMain.versionInfoLogged = false;
+ }
+
+ ///
+ /// Initializes a new instance of the class using default parameters.
+ ///
+ /// Uses the default values: port=COM1, baud rate=19200, timeout=300ms.
+ public GsmCommMain()
+ {
+ this.logLevel = LogLevel.Verbose;
+ this.theDevice = new GsmPhone("COM1", 19200, 300);
+ this.theDevice.LogLevel = this.logLevel;
+ }
+
+ ///
+ /// Initializes a new instance of the class using the specified parameters.
+ ///
+ /// The communication (COM) port to use.
+ /// Uses the default values: baud rate=19200, timeout=300ms.
+ public GsmCommMain(string portName)
+ {
+ this.logLevel = LogLevel.Verbose;
+ this.theDevice = new GsmPhone(portName, 19200, 300);
+ this.theDevice.LogLevel = this.logLevel;
+ }
+
+ ///
+ /// Initializes a new instance of the class using the specified parameters.
+ ///
+ /// The communication (COM) port to use.
+ /// Uses the default values: baud rate=19200, timeout=300ms.
+ public GsmCommMain(int portNumber)
+ {
+ this.logLevel = LogLevel.Verbose;
+ this.theDevice = new GsmPhone(portNumber, 19200, 300);
+ this.theDevice.LogLevel = this.logLevel;
+ }
+
+ ///
+ /// Initializes a new instance of the class using the specified parameters.
+ ///
+ /// The communication (COM) port to use.
+ /// The baud rate (speed) to use.
+ /// Uses the default values: timeout=300ms.
+ public GsmCommMain(string portName, int baudRate)
+ {
+ this.logLevel = LogLevel.Verbose;
+ this.theDevice = new GsmPhone(portName, baudRate, 300);
+ this.theDevice.LogLevel = this.logLevel;
+ }
+
+ ///
+ /// Initializes a new instance of the class using the specified parameters.
+ ///
+ /// The communication (COM) port to use.
+ /// The baud rate (speed) to use.
+ /// Uses the default values: timeout=300ms.
+ public GsmCommMain(int portNumber, int baudRate)
+ {
+ this.logLevel = LogLevel.Verbose;
+ this.theDevice = new GsmPhone(portNumber, baudRate, 300);
+ this.theDevice.LogLevel = this.logLevel;
+ }
+
+ ///
+ /// Initializes a new instance of the class using the specified parameters.
+ ///
+ /// The communication (COM) port to use.
+ /// The baud rate (speed) to use.
+ /// The communication timeout in milliseconds.
+ public GsmCommMain(string portName, int baudRate, int timeout)
+ {
+ this.logLevel = LogLevel.Verbose;
+ this.theDevice = new GsmPhone(portName, baudRate, timeout);
+ this.theDevice.LogLevel = this.logLevel;
+ }
+
+ ///
+ /// Initializes a new instance of the class using the specified parameters.
+ ///
+ /// The communication (COM) port to use.
+ /// The baud rate (speed) to use.
+ /// The communication timeout in milliseconds.
+ public GsmCommMain(int portNumber, int baudRate, int timeout)
+ {
+ this.logLevel = LogLevel.Verbose;
+ this.theDevice = new GsmPhone(portNumber, baudRate, timeout);
+ this.theDevice.LogLevel = this.logLevel;
+ }
+
+ ///
+ /// Acknowledges a new received short message that was directly routed to the application.
+ ///
+ /// Acknowledges are required for most received messages if
+ /// returns true. The acknowledge requirement can be changed with the
+ /// method.
+ ///
+ public void AcknowledgeNewMessage()
+ {
+ this.theDevice.AcknowledgeNewMessage();
+ }
+
+ private void AsyncCallback(IAsyncResult ar)
+ {
+ AsyncResult asyncResult = (AsyncResult)ar;
+ if (asyncResult.AsyncDelegate as GsmCommMain.MessageEventHandler == null)
+ {
+ if (asyncResult.AsyncDelegate as GsmCommMain.MessageErrorEventHandler == null)
+ {
+ this.LogIt(LogLevel.Warning, string.Concat("AsyncCallback got unknown delegate: ", asyncResult.AsyncDelegate.GetType().ToString()));
+ return;
+ }
+ else
+ {
+ this.LogIt(LogLevel.Info, "Ending async MessageErrorEventHandler call");
+ GsmCommMain.MessageErrorEventHandler asyncDelegate = (GsmCommMain.MessageErrorEventHandler)asyncResult.AsyncDelegate;
+ asyncDelegate.EndInvoke(ar);
+ return;
+ }
+ }
+ else
+ {
+ this.LogIt(LogLevel.Info, "Ending async MessageEventHandler call");
+ GsmCommMain.MessageEventHandler messageEventHandler = (GsmCommMain.MessageEventHandler)asyncResult.AsyncDelegate;
+ messageEventHandler.EndInvoke(ar);
+ return;
+ }
+ }
+
+ ///
+ /// Closes the connection to the device.
+ ///
+ /// You can check the current connection state with the method.
+ ///
+ ///
+ ///
+ public void Close()
+ {
+ this.theDevice.Close();
+ this.DisconnectEvents();
+ }
+
+ private void ConnectEvents()
+ {
+ this.theDevice.LoglineAdded += new LoglineAddedEventHandler(this.theDevice_LoglineAdded);
+ this.theDevice.ReceiveProgress += new ProgressEventHandler(this.theDevice_ReceiveProgress);
+ this.theDevice.ReceiveComplete += new ProgressEventHandler(this.theDevice_ReceiveComplete);
+ this.theDevice.MessageReceived += new MessageReceivedEventHandler(this.theDevice_MessageReceived);
+ this.theDevice.PhoneConnected += new EventHandler(this.theDevice_PhoneConnected);
+ this.theDevice.PhoneDisconnected += new EventHandler(this.theDevice_PhoneDisconnected);
+ }
+
+ ///
+ /// Creates a new phonebook entry.
+ ///
+ /// The entry to create.
+ /// The storage to save the entry.
+ /// The property of the entry is ignored,
+ /// the entry is always saved in the first free location. All other properties must be set
+ /// correctly.
+ ///
+ public void CreatePhonebookEntry(PhonebookEntry entry, string storage)
+ {
+ this.theDevice.SelectPhonebookStorage(storage);
+ this.theDevice.WritePhonebookEntry(entry);
+ }
+
+ ///
+ /// Decodes a received short message.
+ ///
+ /// The message to decode
+ /// The decoded message as object.
+ public SmsPdu DecodeReceivedMessage(ShortMessage message)
+ {
+ IncomingSmsPdu incomingSmsPdu = null;
+ try
+ {
+ incomingSmsPdu = IncomingSmsPdu.Decode(message.Data, true, message.Length);
+ }
+ catch (Exception exception1)
+ {
+ Exception exception = exception1;
+ this.LogIt(LogLevel.Error, string.Concat("IncomingSmsPdu decoder can't decode message: ", exception.Message));
+ this.LogIt(LogLevel.Error, string.Concat(" Message data = \"", message.Data, "\""));
+ int length = message.Length;
+ this.LogIt(LogLevel.Error, string.Concat(" Message length = ", length.ToString()));
+ throw;
+ }
+ return incomingSmsPdu;
+ }
+
+ ///
+ /// Decodes a short message read from the phone.
+ ///
+ /// The message to decode.
+ /// The decoded short message.
+ ///
+ /// Use this function to decode messages that were read with the function.
+ ///
+ ///
+ /// There is no decoder available that can handle the message's status.
+ public SmsPdu DecodeShortMessage(ShortMessageFromPhone message)
+ {
+ PhoneMessageStatus status = (PhoneMessageStatus)message.Status;
+ SmsPdu smsPdu = null;
+ PhoneMessageStatus phoneMessageStatu = status;
+ if (phoneMessageStatu == PhoneMessageStatus.ReceivedUnread || phoneMessageStatu == PhoneMessageStatus.ReceivedRead)
+ {
+ try
+ {
+ smsPdu = this.DecodeReceivedMessage(message);
+ }
+ catch (Exception exception)
+ {
+ this.LogIt(LogLevel.Warning, "Unable to decode message with specified status - trying other variants.");
+ smsPdu = this.DecodeStoredMessage(message);
+ }
+ }
+ else if (phoneMessageStatu == PhoneMessageStatus.StoredUnsent || phoneMessageStatu == PhoneMessageStatus.StoredSent)
+ {
+ try
+ {
+ smsPdu = this.DecodeStoredMessage(message);
+ }
+ catch (Exception exception1)
+ {
+ this.LogIt(LogLevel.Warning, "Unable to decode message with specified status - trying other variants.");
+ smsPdu = this.DecodeReceivedMessage(message);
+ }
+ }
+ else
+ {
+ string[] str = new string[5];
+ str[0] = "No decoder available for message of status \"";
+ str[1] = status.ToString();
+ str[2] = "\" (index ";
+ int index = message.Index;
+ str[3] = index.ToString();
+ str[4] = ").";
+ string str1 = string.Concat(str);
+ this.LogIt(LogLevel.Error, str1);
+ throw new CommException(str1);
+ }
+ return smsPdu;
+ }
+
+ private SmsPdu DecodeStoredMessage(ShortMessage message)
+ {
+ OutgoingSmsPdu outgoingSmsPdu = null;
+ try
+ {
+ outgoingSmsPdu = OutgoingSmsPdu.Decode(message.Data, true, message.Length);
+ }
+ catch (Exception exception1)
+ {
+ Exception exception = exception1;
+ this.LogIt(LogLevel.Error, string.Concat("OutgoingSmsPdu decoder can't decode message: ", exception.Message));
+ this.LogIt(LogLevel.Error, string.Concat(" Message data = \"", message.Data, "\""));
+ int length = message.Length;
+ this.LogIt(LogLevel.Error, string.Concat(" Message length = ", length.ToString()));
+ throw;
+ }
+ return outgoingSmsPdu;
+ }
+
+ ///
+ /// Deletes all phonebook entries.
+ ///
+ /// The storage to use.
+ /// To delete single entries, use the function.
+ ///
+ ///
+ public void DeleteAllPhonebookEntries(string storage)
+ {
+ this.theDevice.SelectPhonebookStorage(storage);
+ PhonebookEntry[] phonebookEntryArray = this.theDevice.ReadPhonebookEntries();
+ PhonebookEntry[] phonebookEntryArray1 = phonebookEntryArray;
+ for (int i = 0; i < (int)phonebookEntryArray1.Length; i++)
+ {
+ PhonebookEntry phonebookEntry = phonebookEntryArray1[i];
+ this.theDevice.DeletePhonebookEntry(phonebookEntry.Index);
+ }
+ }
+
+ ///
+ /// Deletes the specified short message.
+ ///
+ /// The index of the message to delete.
+ /// The storage to use.
+ ///
+ /// To delete a group of messages, use the function.
+ ///
+ ///
+ public void DeleteMessage(int index, string storage)
+ {
+ this.LogIt(LogLevel.Info, "Deleting message...");
+ this.theDevice.SelectReadStorage(storage);
+ this.theDevice.DeleteMessage(index);
+ }
+
+ ///
+ /// Deletes the specified group of messages.
+ ///
+ /// Specifies the messages that are affected by this command.
+ /// The storage to use.
+ ///
+ /// To delete a single message, use the function.
+ ///
+ ///
+ public void DeleteMessages(DeleteScope scope, string storage)
+ {
+ int num = scope;
+ DeleteFlag deleteFlag = (DeleteFlag)Enum.Parse(typeof(DeleteFlag), num.ToString());
+ string[] str = new string[5];
+ str[0] = "Deleting \"";
+ str[1] = scope.ToString();
+ str[2] = "\" messages in storage \"";
+ str[3] = storage;
+ str[4] = "\"...";
+ this.LogIt(LogLevel.Info, string.Concat(str));
+ this.theDevice.SelectReadStorage(storage);
+ this.theDevice.DeleteMessage(1, deleteFlag);
+ }
+
+ ///
+ /// Deletes a phonebook entry.
+ ///
+ /// The index of the entry to delete.
+ /// The storage to use.
+ /// To delete all phonebook entries at once, use the
+ /// function.
+ ///
+ ///
+ ///
+ public void DeletePhonebookEntry(int index, string storage)
+ {
+ this.theDevice.SelectPhonebookStorage(storage);
+ this.theDevice.DeletePhonebookEntry(index);
+ }
+
+ ///
+ /// Disables all message notifications.
+ ///
+ ///
+ /// Call this function after a call to to disable this functionality
+ /// again.
+ /// It's highly recommended to disable notifications again before closing the connection to
+ /// the phone. If it doesn't get disabled, the phone will still try to send notifications, which will not be
+ /// successful. The phone may buffer unsuccessful notifications, but you should generally not rely
+ /// on this.
+ ///
+ ///
+ public void DisableMessageNotifications()
+ {
+ this.theDevice.SetMessageIndications(new MessageIndicationSettings(0, 0, 0, 0, 0));
+ }
+
+ ///
+ /// Disables all message routings.
+ ///
+ ///
+ /// Call this function after a call to to disable this functionality
+ /// again.
+ /// CAUTION: It's highly recommended to disable routing again before closing the connection to
+ /// the phone. If it doesn't get disabled, the phone will still try to route messages on, which will not be
+ /// successful. You may lose messages in such a case if the phone doesn't buffer unsuccessful routings.
+ ///
+ ///
+ ///
+ public void DisableMessageRouting()
+ {
+ this.theDevice.SetMessageIndications(new MessageIndicationSettings(0, 0, 0, 0, 0));
+ }
+
+ ///
+ /// Disables the SMS batch mode.
+ ///
+ /// Disables the SMS batch mode previously enabled with
+ /// or .
+ ///
+ public void DisableSmsBatchMode()
+ {
+ this.theDevice.SetMoreMessagesToSend(MoreMessagesMode.Disabled);
+ }
+
+ private void DisconnectEvents()
+ {
+ this.theDevice.LoglineAdded -= new LoglineAddedEventHandler(this.theDevice_LoglineAdded);
+ this.theDevice.ReceiveProgress -= new ProgressEventHandler(this.theDevice_ReceiveProgress);
+ this.theDevice.ReceiveComplete -= new ProgressEventHandler(this.theDevice_ReceiveComplete);
+ this.theDevice.MessageReceived -= new MessageReceivedEventHandler(this.theDevice_MessageReceived);
+ this.theDevice.PhoneConnected -= new EventHandler(this.theDevice_PhoneConnected);
+ this.theDevice.PhoneDisconnected -= new EventHandler(this.theDevice_PhoneDisconnected);
+ }
+
+ ///
+ /// Enables notifications of new received short messages.
+ ///
+ ///
+ /// When a new message is received that is either a standard SMS message or a status report,
+ /// the event is fired. The
+ /// in this event must be cast to a object, which contains the memory
+ /// location of the message that was saved in the phone. You can then use the
+ /// method (for example) to read the new message.
+ /// The supported notification settings vary between different phone models. Therefore the phone is
+ /// queried first and then the supported settings of the phone are compared to the settings needed for
+ /// the notification functionality to work. If a specific setting is not supported and there is no
+ /// alternative setting possible, an exception will be raised.
+ /// To disable message notifications, use the function.
+ ///
+ /// EnableMessageNotifications can't be used with at the same time.
+ /// Disable one functionality before using the other.
+ ///
+ ///
+ ///
+ ///
+ public void EnableMessageNotifications()
+ {
+ MessageIndicationSupport supportedIndications = this.theDevice.GetSupportedIndications();
+ MessageIndicationMode messageIndicationMode = MessageIndicationMode.BufferAndFlush;
+ if (!supportedIndications.SupportsMode(messageIndicationMode))
+ {
+ if (supportedIndications.SupportsMode(MessageIndicationMode.SkipWhenReserved))
+ {
+ messageIndicationMode = MessageIndicationMode.SkipWhenReserved;
+ }
+ else
+ {
+ if (supportedIndications.SupportsMode(MessageIndicationMode.ForwardAlways))
+ {
+ messageIndicationMode = MessageIndicationMode.ForwardAlways;
+ }
+ else
+ {
+ throw new CommException("The phone does not support any of the required message indication modes.");
+ }
+ }
+ }
+ SmsDeliverIndicationStyle smsDeliverIndicationStyle = SmsDeliverIndicationStyle.RouteMemoryLocation;
+ if (supportedIndications.SupportsDeliverStyle(smsDeliverIndicationStyle))
+ {
+ CbmIndicationStyle cbmIndicationStyle = CbmIndicationStyle.Disabled;
+ SmsStatusReportIndicationStyle smsStatusReportIndicationStyle = SmsStatusReportIndicationStyle.RouteMemoryLocation;
+ if (!supportedIndications.SupportsStatusReportStyle(smsStatusReportIndicationStyle))
+ {
+ this.LogIt(LogLevel.Warning, "Attention: The phone does not support notification about new status reports. As a fallback it will be disabled.");
+ smsStatusReportIndicationStyle = SmsStatusReportIndicationStyle.Disabled;
+ }
+ IndicationBufferSetting indicationBufferSetting = IndicationBufferSetting.Flush;
+ if (!supportedIndications.SupportsBufferSetting(indicationBufferSetting))
+ {
+ if (supportedIndications.SupportsBufferSetting(IndicationBufferSetting.Clear))
+ {
+ indicationBufferSetting = IndicationBufferSetting.Clear;
+ }
+ else
+ {
+ throw new CommException("The phone does not support any of the required buffer settings.");
+ }
+ }
+ MessageIndicationSettings messageIndicationSetting = new MessageIndicationSettings(messageIndicationMode, smsDeliverIndicationStyle, cbmIndicationStyle, smsStatusReportIndicationStyle, indicationBufferSetting);
+ this.theDevice.SetMessageIndications(messageIndicationSetting);
+ return;
+ }
+ else
+ {
+ throw new CommException("The phone does not support notification for standard SMS (SMS-DELIVER) messages. ");
+ }
+ }
+
+ ///
+ /// Enables direct routing of new received short messages to the application.
+ ///
+ ///
+ /// When a new message is received that is either a standard SMS message or a status report,
+ /// the event is fired. The
+ /// in this event must be cast to a object which can then be decoded using
+ /// .
+ /// CAUTION: Because the messages are forwared directly, they are not saved in the phone.
+ /// If for some reason the message must be saved it must explicitly be done afterwards. Either by using
+ /// the or functions
+ /// to write the message back to the phone or by storing the message somewhere else for later use.
+ /// It may be necessary to acknlowledge new routed messages to the phone, either because this
+ /// is desired for reliable message transfer or because it is preconfigured in the phone. Use
+ /// to find out if acknowledgements must be done. To do the actual
+ /// acknowledge, use .
+ /// The supported routing settings vary between different phone models. Therefore the phone is
+ /// queried first and then the supported settings of the phone are compared to the settings needed for
+ /// the routing functionality to work. If a specific setting is not supported and there is no
+ /// alternative setting possible, an exception will be raised.
+ /// To disable message routing, use the function.
+ /// EnableMessageRouting can't be used with at the same time.
+ /// Disable one functionality before using the other.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void EnableMessageRouting()
+ {
+ MessageIndicationSupport supportedIndications = this.theDevice.GetSupportedIndications();
+ MessageIndicationMode messageIndicationMode = MessageIndicationMode.BufferAndFlush;
+ if (!supportedIndications.SupportsMode(messageIndicationMode))
+ {
+ if (supportedIndications.SupportsMode(MessageIndicationMode.SkipWhenReserved))
+ {
+ messageIndicationMode = MessageIndicationMode.SkipWhenReserved;
+ }
+ else
+ {
+ if (supportedIndications.SupportsMode(MessageIndicationMode.ForwardAlways))
+ {
+ messageIndicationMode = MessageIndicationMode.ForwardAlways;
+ }
+ else
+ {
+ throw new CommException("The phone does not support any of the required message indication modes.");
+ }
+ }
+ }
+ SmsDeliverIndicationStyle smsDeliverIndicationStyle = SmsDeliverIndicationStyle.RouteMessage;
+ if (supportedIndications.SupportsDeliverStyle(smsDeliverIndicationStyle))
+ {
+ CbmIndicationStyle cbmIndicationStyle = CbmIndicationStyle.Disabled;
+ SmsStatusReportIndicationStyle smsStatusReportIndicationStyle = SmsStatusReportIndicationStyle.RouteMessage;
+ if (!supportedIndications.SupportsStatusReportStyle(smsStatusReportIndicationStyle))
+ {
+ this.LogIt(LogLevel.Warning, "Attention: The phone does not support routing of new status reports. As a fallback it will be disabled.");
+ smsStatusReportIndicationStyle = SmsStatusReportIndicationStyle.Disabled;
+ }
+ IndicationBufferSetting indicationBufferSetting = IndicationBufferSetting.Flush;
+ if (!supportedIndications.SupportsBufferSetting(indicationBufferSetting))
+ {
+ if (supportedIndications.SupportsBufferSetting(IndicationBufferSetting.Clear))
+ {
+ indicationBufferSetting = IndicationBufferSetting.Clear;
+ }
+ else
+ {
+ throw new CommException("The phone does not support any of the required buffer settings.");
+ }
+ }
+ MessageIndicationSettings messageIndicationSetting = new MessageIndicationSettings(messageIndicationMode, smsDeliverIndicationStyle, cbmIndicationStyle, smsStatusReportIndicationStyle, indicationBufferSetting);
+ this.theDevice.SetMessageIndications(messageIndicationSetting);
+ return;
+ }
+ else
+ {
+ throw new CommException("The phone does not support routing of standard SMS (SMS-DELIVER) messages.");
+ }
+ }
+
+ ///
+ /// Enables the SMS batch mode permanently.
+ ///
+ ///
+ /// When this feature is enabled (and supported by the network), multiple messages can be sent much
+ /// faster, as the SMS link is kept open between the messages.
+ /// If there is no message sent for 1-5 seconds (the exact value is up to the phones's implementation)
+ /// after the last sent SMS message, the SMS link is closed but the batch mode is kept enabled. You have
+ /// to explicitely disable it with .
+ /// If you don't want to care about turning the batch mode off when done with sending,
+ /// consider using instead.
+ ///
+ public void EnablePermanentSmsBatchMode()
+ {
+ this.theDevice.SetMoreMessagesToSend(MoreMessagesMode.Permanent);
+ }
+
+ ///
+ /// Enables the SMS batch mode temporarily.
+ ///
+ ///
+ /// When this feature is enabled (and supported by the network), multiple messages can be sent much
+ /// faster, as the SMS link is kept open between the messages.
+ /// If there is no message sent for 1-5 seconds (the exact value is up to the phones's implementation)
+ /// after the last sent SMS message, the SMS link is closed and the batch mode is disabled
+ /// automatically. You have to re-enable it before you send the next batch of messages, but you
+ /// also don't have to care about turning it off when finished with sending.
+ ///
+ public void EnableTemporarySmsBatchMode()
+ {
+ this.theDevice.SetMoreMessagesToSend(MoreMessagesMode.Temporary);
+ }
+
+ ///
+ /// Enters a password at the phone which is necessary before it can operated.
+ ///
+ /// The SIM PIN, SIM PUK or other password required.
+ /// Get the current PIN status with to check
+ /// whether a password must be entered.
+ public void EnterPin(string pin)
+ {
+ this.theDevice.EnterPin(pin);
+ }
+
+ ///
+ /// Finds phonebook entries.
+ ///
+ /// The text in the entry to find.
+ /// The storage to search.
+ /// An array of phonebook entries matching the specified criteria.
+ /// The device executes the actual search. If you need the storage information with the results,
+ /// use the function instead.
+ ///
+ ///
+ public PhonebookEntry[] FindPhonebookEntries(string findtext, string storage)
+ {
+ new ArrayList();
+ this.theDevice.SelectPhonebookStorage(storage);
+ return this.theDevice.FindPhonebookEntries(findtext);
+ }
+
+ ///
+ /// Finds phonebook entries and saves the storage where they came from.
+ ///
+ /// The text in the entry to find.
+ /// The storage to search.
+ /// An array of phonebook entries matching the specified criteria.
+ /// The device executes the actual search. If you don't need the storage information with the
+ /// results, use the function instead.
+ ///
+ ///
+ public PhonebookEntryWithStorage[] FindPhonebookEntriesWithStorage(string findtext, string storage)
+ {
+ ArrayList arrayLists = new ArrayList();
+ this.theDevice.SelectPhonebookStorage(storage);
+ PhonebookEntry[] phonebookEntryArray = this.theDevice.FindPhonebookEntries(findtext);
+ for (int i = 0; i < (int)phonebookEntryArray.Length; i++)
+ {
+ PhonebookEntry phonebookEntry = phonebookEntryArray[i];
+ arrayLists.Add(new PhonebookEntryWithStorage(phonebookEntry, storage));
+ }
+ PhonebookEntryWithStorage[] phonebookEntryWithStorageArray = new PhonebookEntryWithStorage[arrayLists.Count];
+ arrayLists.CopyTo(phonebookEntryWithStorageArray, 0);
+ return phonebookEntryWithStorageArray;
+ }
+
+ ///
+ /// Gets the phone's battery charging status.
+ ///
+ /// A object containing the battery details.
+ public BatteryChargeInfo GetBatteryCharge()
+ {
+ return this.theDevice.GetBatteryCharge();
+ }
+
+ ///
+ /// Gets the currenty selected text mode character set.
+ ///
+ /// A string containing the name of the currently selected character set.
+ ///
+ ///
+ ///
+ ///
+ public string GetCurrentCharacterSet()
+ {
+ return this.theDevice.GetCurrentCharacterSet();
+ }
+
+ ///
+ /// AT+COPS. Gets the currently selected network operator.
+ ///
+ /// An object containing the data or null if there is no current operator.
+ public OperatorInfo GetCurrentOperator()
+ {
+ return this.theDevice.GetCurrentOperator();
+ }
+
+ ///
+ /// Gets the memory status of the specified message storage.
+ ///
+ /// The storage to return the status for
+ /// An object containing the memory status of the specified storage.
+ public MemoryStatus GetMessageMemoryStatus(string storage)
+ {
+ return this.theDevice.SelectReadStorage(storage);
+ }
+
+ ///
+ /// Gets the device's supported message storages.
+ ///
+ /// A object that contains details about the supported storages.
+ public MessageStorageInfo GetMessageStorages()
+ {
+ return this.theDevice.GetMessageStorages();
+ }
+
+ ///
+ /// Determines the current mode to select a network operator.
+ ///
+ /// The current mode.
+ public OperatorSelectionMode GetOperatorSelectionMode()
+ {
+ int operatorSelectionMode = this.theDevice.GetOperatorSelectionMode();
+ if (Enum.IsDefined(typeof(OperatorSelectionMode), operatorSelectionMode))
+ {
+ OperatorSelectionMode operatorSelectionMode1 = (OperatorSelectionMode)Enum.Parse(typeof(OperatorSelectionMode), operatorSelectionMode.ToString());
+ return operatorSelectionMode1;
+ }
+ else
+ {
+ throw new CommException(string.Concat("Unknown operator selection mode ", operatorSelectionMode));
+ }
+ }
+
+ ///
+ /// Gets the entire phonebook of the selected storage.
+ ///
+ /// The storage to read the data from.
+ /// An array of phonebook entries. If you need the storage information with the
+ /// results, use the function instead.
+ ///
+ ///
+ ///
+ public PhonebookEntry[] GetPhonebook(string storage)
+ {
+ new ArrayList();
+ this.theDevice.SelectPhonebookStorage(storage);
+ return this.theDevice.ReadPhonebookEntries();
+ }
+
+ ///
+ /// Gets the memory status of the specified phonebook storage.
+ ///
+ /// The storage to return the status for
+ /// An object containing the memory status of the specified storage.
+ public MemoryStatusWithStorage GetPhonebookMemoryStatus(string storage)
+ {
+ this.theDevice.SelectPhonebookStorage(storage);
+ return this.theDevice.GetPhonebookMemoryStatus();
+ }
+
+ ///
+ /// Gets the device's supported phonebook storages.
+ ///
+ /// An array of supported storages in coded form, usually "SM" for SIM, "ME" for
+ /// phone, etc.
+ public string[] GetPhonebookStorages()
+ {
+ return this.theDevice.GetPhonebookStorages();
+ }
+
+ ///
+ /// Gets the entire phonebook of the selected storage and saves the storage where the entries came from.
+ ///
+ /// The storage to read the data from.
+ /// An array of phonebook entries. If you don't need the storage information with the
+ /// results, use the function instead.
+ ///
+ ///
+ ///
+ public PhonebookEntryWithStorage[] GetPhonebookWithStorage(string storage)
+ {
+ ArrayList arrayLists = new ArrayList();
+ this.theDevice.SelectPhonebookStorage(storage);
+ PhonebookEntry[] phonebookEntryArray = this.theDevice.ReadPhonebookEntries();
+ for (int i = 0; i < (int)phonebookEntryArray.Length; i++)
+ {
+ PhonebookEntry phonebookEntry = phonebookEntryArray[i];
+ arrayLists.Add(new PhonebookEntryWithStorage(phonebookEntry, storage));
+ }
+ PhonebookEntryWithStorage[] phonebookEntryWithStorageArray = new PhonebookEntryWithStorage[arrayLists.Count];
+ arrayLists.CopyTo(phonebookEntryWithStorageArray, 0);
+ return phonebookEntryWithStorageArray;
+ }
+
+ ///
+ /// Returns a value indicating whether some password must be entered at the phone or not.
+ ///
+ /// The current PIN status as one of the values.
+ public PinStatus GetPinStatus()
+ {
+ return this.theDevice.GetPinStatus();
+ }
+
+ ///
+ /// Enables access to the protocol level of the current connection.
+ ///
+ /// An object that sends and receives data at the protocol level.
+ /// This method enables execution of custom commands that are not directly supported. It also disables execution of background
+ /// operations that would usually take place, such as checking whether the phone is still connected.
+ /// The method must be called as soon as execution of the custom commands is completed,
+ /// and allows for normal operations to continue. Execution of other commands besides from is not allowed
+ /// until is called.
+ ///
+ ///
+ public IProtocol GetProtocol()
+ {
+ return this.theDevice.GetProtocol();
+ }
+
+ ///
+ /// Gets the signal quality as calculated by the phone.
+ ///
+ /// A object containing the signal details.
+ public SignalQualityInfo GetSignalQuality()
+ {
+ return this.theDevice.GetSignalQuality();
+ }
+
+ ///
+ /// Gets the current SMS batch mode setting.
+ ///
+ /// The current mode.
+ public MoreMessagesMode GetSmsBatchModeSetting()
+ {
+ return this.theDevice.GetMoreMessagesToSend();
+ }
+
+ ///
+ /// Gets the SMS Service Center Address.
+ ///
+ /// The current SMSC address
+ /// This command returns the SMSC address, through which SMS messages are transmitted.
+ /// In text mode, this setting is used by SMS sending and SMS writing commands. In PDU mode, this setting is
+ /// used by the same commands, but only when the length of the SMSC address coded into the PDU data equals
+ /// zero.
+ public AddressData GetSmscAddress()
+ {
+ return this.theDevice.GetSmscAddress();
+ }
+
+ ///
+ /// Returns the MSISDNs related to the subscriber.
+ ///
+ /// An array of objects with one for each MSISDN
+ /// (Mobile Subscriber ISDN Number), depending on the services subscribed.
+ ///
+ /// This information can be stored in the SIM/UICC or in the MT.
+ /// If the command is supported by the phone but no number can be retrieved,
+ /// an empty array is returned.
+ ///
+ public SubscriberInfo[] GetSubscriberNumbers()
+ {
+ return this.theDevice.GetSubscriberNumbers();
+ }
+
+ ///
+ /// Gets the phone's supported text mode character sets.
+ ///
+ /// A string array containing the names of the phone's supportet text mode character sets.
+ ///
+ ///
+ ///
+ ///
+ public string[] GetSupportedCharacterSets()
+ {
+ return this.theDevice.GetSupportedCharacterSets();
+ }
+
+ ///
+ /// Gathers information that identifiy the connected device.
+ ///
+ /// An object containing data about the device.
+ public IdentificationInfo IdentifyDevice()
+ {
+ this.LogIt(LogLevel.Info, "Identifying device...");
+ IdentificationInfo identificationInfo = new IdentificationInfo();
+ identificationInfo.Manufacturer = this.theDevice.RequestManufacturer();
+ identificationInfo.Model = this.theDevice.RequestModel();
+ identificationInfo.Revision = this.theDevice.RequestRevision();
+ identificationInfo.SerialNumber = this.theDevice.RequestSerialNumber();
+ this.LogIt(LogLevel.Info, string.Concat("Manufacturer: ", identificationInfo.Manufacturer));
+ this.LogIt(LogLevel.Info, string.Concat("Model: ", identificationInfo.Model));
+ this.LogIt(LogLevel.Info, string.Concat("Revision: ", identificationInfo.Revision));
+ this.LogIt(LogLevel.Info, string.Concat("Serial number: ", identificationInfo.SerialNumber));
+ return identificationInfo;
+ }
+
+ ///
+ /// Checks if it is required to acknowledge new directly routed incoming messages.
+ ///
+ /// true if directly routed incoming messages need to be acknowledged, false if not.
+ public bool IsAcknowledgeRequired()
+ {
+ int num = 0;
+ int num1 = 0;
+ int num2 = 0;
+ int num3 = 0;
+ this.theDevice.GetCurrentMessageService(out num, out num1, out num2, out num3);
+ return num == 1;
+ }
+
+ ///
+ /// Determines if there is actually a device connected that responds to commands.
+ ///
+ /// true if there is a device connected and responsive, otherwise false.
+ ///
+ /// You can use this function after opening the port with to verify that there is really a device connected
+ /// before processding.
+ ///
+ ///
+ ///
+ public bool IsConnected()
+ {
+ return this.theDevice.IsConnected();
+ }
+
+ ///
+ /// Determines if the port is currently open.
+ ///
+ /// true if the port is open, otherwise false.
+ /// The port is open after a auccessful call to and must be closed with
+ /// .
+ /// This function does not check if there is actually a device connected, use the
+ /// function for that.
+ ///
+ ///
+ ///
+ ///
+ public bool IsOpen()
+ {
+ return this.theDevice.IsOpen();
+ }
+
+ ///
+ /// Lists the network operators detected by the phone.
+ ///
+ /// An array of objects containing the data of each operator.
+ /// If you want to determine the current operator, use the method.
+ public OperatorInfo2[] ListOperators()
+ {
+ return this.theDevice.ListOperators();
+ }
+
+ private void LogIt(LogLevel level, string text)
+ {
+ if (this.LoglineAdded != null && level <= this.logLevel)
+ {
+ DateTime now = DateTime.Now;
+ text = string.Concat(now.ToString("HH:mm:ss.fff"), " ", text);
+ this.LoglineAdded(this, new LoglineAddedEventArgs(level, text));
+ }
+ }
+
+ private void LogVersionInfo()
+ {
+ Assembly executingAssembly = Assembly.GetExecutingAssembly();
+ Version version = executingAssembly.GetName().Version;
+ string str = version.ToString(2);
+ string str1 = version.ToString();
+ string imageRuntimeVersion = executingAssembly.ImageRuntimeVersion;
+ string str2 = string.Format("GSMComm {0} (Build {1} for .NET {2})", str, str1, imageRuntimeVersion);
+ this.LogIt(LogLevel.Info, str2);
+ }
+
+ private void OnMessageSendComplete(OutgoingSmsPdu pdu)
+ {
+ if (this.MessageSendComplete != null)
+ {
+ this.LogIt(LogLevel.Info, "Firing async MessageSendComplete event.");
+ MessageEventArgs messageEventArg = new MessageEventArgs(pdu);
+ this.MessageSendComplete.BeginInvoke(this, messageEventArg, new AsyncCallback(this.AsyncCallback), null);
+ }
+ }
+
+ private void OnMessageSendFailed(OutgoingSmsPdu pdu, Exception exception)
+ {
+ if (this.MessageSendFailed != null)
+ {
+ this.LogIt(LogLevel.Info, "Firing async MessageSendFailed event.");
+ MessageErrorEventArgs messageErrorEventArg = new MessageErrorEventArgs(pdu, exception);
+ this.MessageSendFailed.BeginInvoke(this, messageErrorEventArg, new AsyncCallback(this.AsyncCallback), null);
+ }
+ }
+
+ private void OnMessageSendStarting(OutgoingSmsPdu pdu)
+ {
+ if (this.MessageSendStarting != null)
+ {
+ this.LogIt(LogLevel.Info, "Firing async MessageSendStarting event.");
+ MessageEventArgs messageEventArg = new MessageEventArgs(pdu);
+ this.MessageSendStarting.BeginInvoke(this, messageEventArg, new AsyncCallback(this.AsyncCallback), null);
+ }
+ }
+
+ ///
+ /// Opens the connection to the device.
+ ///
+ /// You can check the current connection state with the method.
+ ///
+ ///
+ ///
+ public void Open()
+ {
+ if (!GsmCommMain.versionInfoLogged)
+ {
+ this.LogVersionInfo();
+ GsmCommMain.versionInfoLogged = true;
+ }
+ this.ConnectEvents();
+ this.theDevice.Open();
+ }
+
+ ///
+ /// Reads a single short message.
+ ///
+ /// The index of the message to read.
+ /// The storage to look in for the message.
+ /// A object containing the message at the index specified.
+ public DecodedShortMessage ReadMessage(int index, string storage)
+ {
+ this.LogIt(LogLevel.Info, "Reading message...");
+ this.theDevice.SelectReadStorage(storage);
+ ShortMessageFromPhone shortMessageFromPhone = this.theDevice.ReadMessage(index);
+ if (!Enum.IsDefined(typeof(PhoneMessageStatus), shortMessageFromPhone.Status))
+ {
+ int status = shortMessageFromPhone.Status;
+ throw new CommException(string.Concat("Unknown message status \"", status.ToString(), "\"!"));
+ }
+ else
+ {
+ int num = shortMessageFromPhone.Status;
+ PhoneMessageStatus phoneMessageStatu = (PhoneMessageStatus)Enum.Parse(typeof(PhoneMessageStatus), num.ToString());
+ DecodedShortMessage decodedShortMessage = new DecodedShortMessage(shortMessageFromPhone.Index, this.DecodeShortMessage(shortMessageFromPhone), phoneMessageStatu, storage);
+ return decodedShortMessage;
+ }
+ }
+
+ ///
+ /// Reads and decodes short messages from phone.
+ ///
+ /// The status of the messages to read.
+ /// The storage to look in for the messages.
+ /// An array of decoded messages.
+ /// As the decoded version of the message is not always guaranteed to
+ /// be exactly the same when encoded back, do not use this function if you want
+ /// to save the message in their original form. Use instead
+ /// for that case.
+ ///
+ ///
+ public DecodedShortMessage[] ReadMessages(PhoneMessageStatus status, string storage)
+ {
+ this.LogIt(LogLevel.Info, "Reading messages...");
+ ArrayList arrayLists = new ArrayList();
+ this.theDevice.SelectReadStorage(storage);
+ ShortMessageFromPhone[] shortMessageFromPhoneArray = this.theDevice.ListMessages(status);
+ for (int i = 0; i < (int)shortMessageFromPhoneArray.Length; i++)
+ {
+ ShortMessageFromPhone shortMessageFromPhone = shortMessageFromPhoneArray[i];
+ try
+ {
+ if (!Enum.IsDefined(typeof(PhoneMessageStatus), shortMessageFromPhone.Status))
+ {
+ int num = shortMessageFromPhone.Status;
+ throw new CommException(string.Concat("Unknown message status \"", num.ToString(), "\"!"));
+ }
+ else
+ {
+ int num1 = shortMessageFromPhone.Status;
+ PhoneMessageStatus phoneMessageStatu = (PhoneMessageStatus)Enum.Parse(typeof(PhoneMessageStatus), num1.ToString());
+ arrayLists.Add(new DecodedShortMessage(shortMessageFromPhone.Index, this.DecodeShortMessage(shortMessageFromPhone), phoneMessageStatu, storage));
+ }
+ }
+ catch (Exception exception1)
+ {
+ Exception exception = exception1;
+ this.LogIt(LogLevel.Error, string.Concat("Error while decoding a message: ", exception.Message, " The message was ignored."));
+ }
+ }
+ DecodedShortMessage[] decodedShortMessageArray = new DecodedShortMessage[arrayLists.Count];
+ arrayLists.CopyTo(decodedShortMessageArray);
+ return decodedShortMessageArray;
+ }
+
+ ///
+ /// Reads short messages in their original form from phone.
+ ///
+ /// The status of the messages to read.
+ /// The storage to look in for the messages.
+ /// An array of undecoded short messages, as read from the phone.
+ /// This function is intended to download the messages exactly as they are
+ /// returned from the phone, e.g. for a backup. If you want to use the messages
+ /// directly, e.g. displaying them to the user without saving them, use the
+ /// function instead.
+ /// If you want to decode the saved messages later, you can use the
+ /// function.
+ /// You can import the saved message back to the phone using the
+ /// function.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public ShortMessageFromPhone[] ReadRawMessages(PhoneMessageStatus status, string storage)
+ {
+ this.LogIt(LogLevel.Info, "Reading messages...");
+ new ArrayList();
+ this.theDevice.SelectReadStorage(storage);
+ return this.theDevice.ListMessages(status);
+ }
+
+ ///
+ /// Disables access to the protocol level of the current connection.
+ ///
+ /// This method must be called as soon as the execution of the custom commands initiated
+ /// by is completed and allows for normal operations to continue.
+ ///
+ public void ReleaseProtocol()
+ {
+ this.theDevice.ReleaseProtocol();
+ }
+
+ ///
+ /// Enables or disables the requirement to acknowledge new received short messages
+ /// that are directly routed to the application.
+ ///
+ /// Set to true to require acknowledgements, set to false
+ /// to turn off the requirement.
+ /// It depends on the phone when this setting can actually be changed.
+ /// Because of this, it is recommended to execute
+ /// after a call to RequireAcknowledge to verify the new setting.
+ ///
+ public void RequireAcknowledge(bool require)
+ {
+ int num = 0;
+ int num1 = 0;
+ int num2 = 0;
+ int num3;
+ if (require)
+ {
+ num3 = 1;
+ }
+ else
+ {
+ num3 = 0;
+ }
+ int num4 = num3;
+ this.theDevice.SelectMessageService(num4, out num, out num1, out num2);
+ }
+
+ ///
+ /// Resets all settings that are not stored in a profile to their factory defaults.
+ ///
+ /// This function is useful if you don't know the state your phone is and
+ /// want to set it up from scratch.
+ public void ResetToDefaultConfig()
+ {
+ this.theDevice.ResetToDefaultConfig();
+ }
+
+ /// Selects the text mode character set.
+ /// The character set to use.
+ ///
+ /// The class contains some common character sets.
+ /// To get a list of the character sets that the phone supports, use .
+ ///
+ ///
+ ///
+ public void SelectCharacterSet(string charset)
+ {
+ this.theDevice.SelectCharacterSet(charset);
+ }
+
+ ///
+ /// Sends a short message.
+ ///
+ /// The object containing the message to send.
+ /// Indicates whether an exception should be
+ /// thrown upon an error.
+ ///
+ /// This method sends the short message contained in the PDU object.
+ /// The message reference returned by the phone is stored in the MessageReference
+ /// property of the PDU object. If there is an error, an exception will be thrown.
+ /// Additionally, this function also fires the event
+ /// upon an error and the event upon success.
+ /// Set the throwExceptions parameter to false if your message handling
+ /// uses only the events fired by this method.
+ /// To send multiple messages in succession, use the function.
+ ///
+ ///
+ public void SendMessage(OutgoingSmsPdu pdu, bool throwExceptions)
+ {
+ this.LogIt(LogLevel.Info, "Sending message...");
+ this.OnMessageSendStarting(pdu);
+ byte num = 0;
+ try
+ {
+ num = this.theDevice.SendMessage(pdu.ToString(), pdu.ActualLength);
+ }
+ catch (Exception exception1)
+ {
+ Exception exception = exception1;
+ this.LogIt(LogLevel.Error, string.Concat("Error while sending the message: ", exception.Message));
+ this.OnMessageSendFailed(pdu, exception);
+ if (!throwExceptions)
+ {
+ return;
+ }
+ else
+ {
+ throw;
+ }
+ }
+ if (pdu.MessageReference == 0)
+ {
+ pdu.MessageReference = num;
+ }
+ this.LogIt(LogLevel.Info, "Message sent successfully.");
+ this.OnMessageSendComplete(pdu);
+ }
+
+ ///
+ /// Sends a short message.
+ ///
+ /// The object containing the message to send.
+ ///
+ /// This method sends the short message contained in the PDU object.
+ /// The message reference returned by the phone is stored in the MessageReference
+ /// property of the PDU object. If there is an error, an exception will be thrown.
+ /// Additionally, this function also fires the event
+ /// upon an error and the event upon success.
+ /// To send multiple messages in succession, use the function.
+ ///
+ ///
+ public void SendMessage(OutgoingSmsPdu pdu)
+ {
+ this.SendMessage(pdu, true);
+ }
+
+ ///
+ /// Sends multiple messages in succession. Sending stops at the first error.
+ ///
+ /// The messages to send.
+ ///
+ ///
+ ///
+ ///
+ public void SendMessages(OutgoingSmsPdu[] pdus)
+ {
+ if (pdus != null)
+ {
+ if ((int)pdus.Length != 0)
+ {
+ int length = (int)pdus.Length;
+ this.LogIt(LogLevel.Info, string.Concat(length.ToString(), " message(s) to send."));
+ for (int i = 0; i < (int)pdus.Length; i++)
+ {
+ OutgoingSmsPdu outgoingSmsPdu = pdus[i];
+ string[] str = new string[5];
+ str[0] = "Sending message ";
+ int num = i + 1;
+ str[1] = num.ToString();
+ str[2] = " of ";
+ int length1 = (int)pdus.Length;
+ str[3] = length1.ToString();
+ str[4] = "...";
+ this.LogIt(LogLevel.Info, string.Concat(str));
+ this.SendMessage(outgoingSmsPdu);
+ }
+ return;
+ }
+ else
+ {
+ this.LogIt(LogLevel.Warning, "Nothing to do!");
+ return;
+ }
+ }
+ else
+ {
+ this.LogIt(LogLevel.Error, "Failed. Message array is null.");
+ throw new ArgumentNullException("pdus");
+ }
+ }
+
+ ///
+ /// Sets the new SMS service center address.
+ ///
+ /// An object containing the new address
+ /// This command changes the SMSC address, through which SMS messages are transmitted.
+ /// In text mode, this setting is used by SMS sending and SMS writing commands. In PDU mode, this setting is
+ /// used by the same commands, but only when the length of the SMSC address coded into the PDU data equals
+ /// zero.
+ public void SetSmscAddress(AddressData data)
+ {
+ this.theDevice.SetSmscAddress(data);
+ }
+
+ ///
+ /// Sets the new SMS service center address.
+ ///
+ /// The new SMSC address
+ /// This command changes the SMSC address, through which SMS messages are transmitted.
+ /// In text mode, this setting is used by SMS sending and SMS writing commands. In PDU mode, this setting is
+ /// used by the same commands, but only when the length of the SMSC address coded into the PDU data equals
+ /// zero.
+ public void SetSmscAddress(string address)
+ {
+ this.theDevice.SetSmscAddress(address);
+ }
+
+ private void theDevice_LoglineAdded(object sender, LoglineAddedEventArgs e)
+ {
+ if (this.LoglineAdded != null)
+ {
+ this.LoglineAdded(this, e);
+ }
+ }
+
+ private void theDevice_MessageReceived(object sender, MessageReceivedEventArgs e)
+ {
+ if (this.MessageReceived != null)
+ {
+ this.MessageReceived(this, e);
+ }
+ }
+
+ private void theDevice_PhoneConnected(object sender, EventArgs e)
+ {
+ if (this.PhoneConnected != null)
+ {
+ this.PhoneConnected(this, e);
+ }
+ }
+
+ private void theDevice_PhoneDisconnected(object sender, EventArgs e)
+ {
+ if (this.PhoneDisconnected != null)
+ {
+ this.PhoneDisconnected(this, e);
+ }
+ }
+
+ private void theDevice_ReceiveComplete(object sender, ProgressEventArgs e)
+ {
+ if (this.ReceiveComplete != null)
+ {
+ this.ReceiveComplete(this, e);
+ }
+ }
+
+ private void theDevice_ReceiveProgress(object sender, ProgressEventArgs e)
+ {
+ if (this.ReceiveProgress != null)
+ {
+ this.ReceiveProgress(this, e);
+ }
+ }
+
+ ///
+ /// Stores a raw short message in the specified storage.
+ ///
+ /// The message to store.
+ /// The storage to store the message in.
+ /// The index of the message. If the index could not be retrieved, zero is returned.
+ ///
+ /// This function is useful for importing messages that were previously exported with .
+ ///
+ ///
+ public int WriteRawMessage(ShortMessageFromPhone message, string storage)
+ {
+ this.theDevice.SelectWriteStorage(storage);
+ return this.theDevice.WriteMessageToMemory(message.Data, message.Length, message.Status);
+ }
+
+ ///
+ /// Stores a raw short message in the specified storage.
+ ///
+ /// The message to store.
+ /// The storage to store the message in.
+ /// The status to set for the message.
+ /// The index of the message. If the index could not be retrieved, zero is returned.
+ public int WriteRawMessage(ShortMessage message, string storage, int status)
+ {
+ this.theDevice.SelectWriteStorage(storage);
+ return this.theDevice.WriteMessageToMemory(message.Data, message.Length, status);
+ }
+
+ ///
+ /// Stores a raw short message in the specified storage without setting a specific message status.
+ ///
+ /// The message to store.
+ /// The storage to store the message in.
+ /// The index of the message. If the index could not be retrieved, zero is returned.
+ ///
+ /// The message is stored with a predefined status set in the phone.
+ ///
+ ///
+ ///
+ public int WriteRawMessageWithoutStatus(ShortMessage message, string storage)
+ {
+ this.theDevice.SelectWriteStorage(storage);
+ return this.theDevice.WriteMessageToMemory(message.Data, message.Length);
+ }
+
+ ///
+ /// The event that occurs when a new line was added to the log.
+ ///
+ public event LoglineAddedEventHandler LoglineAdded;
+
+ ///
+ /// The event that occurs when a new message was received.
+ ///
+ public event MessageReceivedEventHandler MessageReceived;
+
+ ///
+ /// The event that occurs after a successful message transfer.
+ ///
+ public event GsmCommMain.MessageEventHandler MessageSendComplete;
+
+ ///
+ /// The event that occurs after a failed message transfer.
+ ///
+ public event GsmCommMain.MessageErrorEventHandler MessageSendFailed;
+
+ ///
+ /// The event that occurs immediately before transferring a new message.
+ ///
+ public event GsmCommMain.MessageEventHandler MessageSendStarting;
+
+ /// The event that occurs when the phone is connected.
+ public event EventHandler PhoneConnected;
+
+ /// The event that occurs when the phone is disconnected.
+ public event EventHandler PhoneDisconnected;
+
+ /// The event that occurs when receiving from the phone is completed.
+ /// This event is only fired by reading operations that may take longer to complete.
+ public event ProgressEventHandler ReceiveComplete;
+
+ /// The event that occurs when new data was received from the phone.
+ /// This event is only fired by reading operations that may take longer to complete.
+ public event ProgressEventHandler ReceiveProgress;
+
+ ///
+ /// The method that handles the event.
+ ///
+ /// The origin of the event.
+ /// The associated with the event.
+ public delegate void MessageErrorEventHandler(object sender, MessageErrorEventArgs e);
+
+ ///
+ /// The method that handles the and
+ /// events.
+ ///
+ /// The origin of the event.
+ /// The associated with the event.
+ public delegate void MessageEventHandler(object sender, MessageEventArgs e);
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/GsmPhone.cs b/GSMCommunication/GsmCommunication/GsmPhone.cs
new file mode 100644
index 0000000..74485b2
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/GsmPhone.cs
@@ -0,0 +1,3262 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO.Ports;
+using System.Runtime.Remoting.Messaging;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Timers;
+
+///
+/// Interacts with a mobile phone at a low level to execute various functions.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class GsmPhone : IProtocol
+ {
+ private const int receiveTimeout = 5000;
+
+ private const string commOK = "\r\nOK\r\n";
+
+ private const string commError = "\r\nERROR\r\n";
+
+ private const string messageServiceErrorPattern = "\\r\\n\\+CMS ERROR: (\\d+)\\r\\n";
+
+ private const string mobileEquipmentErrorPattern = "\\r\\n\\+CME ERROR: (\\d+)\\r\\n";
+
+ private SerialPort port;
+
+ private string portName;
+
+ private int baudRate;
+
+ private int timeout;
+
+ private bool logEnabled;
+
+ private LogLevel logLevel;
+
+ private int commThreadCheckDelay;
+
+ private Queue rawQueue;
+
+ private Queue inputQueue;
+
+ private ManualResetEvent terminateCommThread;
+
+ private ManualResetEvent dataReceived;
+
+ private ManualResetEvent noData;
+
+ private Thread commThread;
+
+ private string dataToSend;
+
+ private ManualResetEvent sendNow;
+
+ private ManualResetEvent receiveNow;
+
+ private ManualResetEvent sendDone;
+
+ private bool connectionState;
+
+ private AutoResetEvent checkConnection;
+
+ private ManualResetEvent logThreadInitialized;
+
+ private ManualResetEvent terminateLogThread;
+
+ private Queue logQueue;
+
+ private Thread logThread;
+
+ ///
+ /// Gets the baud rate.
+ ///
+ public int BaudRate
+ {
+ get
+ {
+ return this.baudRate;
+ }
+ }
+
+ ///
+ /// Gets or sets the delay in milliseconds between the checks to verify that the connection
+ /// to the phone is still alive.
+ ///
+ public int ConnectionCheckDelay
+ {
+ get
+ {
+ return this.commThreadCheckDelay;
+ }
+ set
+ {
+ int num;
+ if (value < 1000)
+ {
+ num = 1000;
+ }
+ else
+ {
+ num = value;
+ }
+ int num1 = num;
+ this.commThreadCheckDelay = num1;
+ }
+ }
+
+ ///
+ /// Get or sets the current log level for this instance.
+ ///
+ public LogLevel LogLevel
+ {
+ get
+ {
+ return this.logLevel;
+ }
+ set
+ {
+ this.logLevel = value;
+ }
+ }
+
+ ///
+ /// Gets the COM port.
+ ///
+ public string PortName
+ {
+ get
+ {
+ return this.portName;
+ }
+ }
+
+ ///
+ /// Gets the communication timeout.
+ ///
+ public int Timeout
+ {
+ get
+ {
+ return this.timeout;
+ }
+ }
+
+ ///
+ /// Initializing a new instance of the class.
+ ///
+ /// The communication (COM) port to use.
+ /// The baud rate (speed) to use.
+ /// The communication timeout in milliseconds.
+ public GsmPhone(string portName, int baudRate, int timeout)
+ {
+ this.commThreadCheckDelay = 10000;
+ if (portName != null)
+ {
+ if (portName == null || portName.Length != 0)
+ {
+ if (baudRate >= 0)
+ {
+ if (timeout >= 0)
+ {
+ this.port = null;
+ this.portName = portName;
+ this.baudRate = baudRate;
+ this.timeout = timeout;
+ this.logEnabled = true;
+ this.logLevel = LogLevel.Verbose;
+ this.rawQueue = new Queue();
+ this.inputQueue = Queue.Synchronized(this.rawQueue);
+ this.terminateCommThread = new ManualResetEvent(false);
+ this.dataReceived = new ManualResetEvent(false);
+ this.noData = new ManualResetEvent(false);
+ this.commThread = null;
+ this.dataToSend = string.Empty;
+ this.sendNow = new ManualResetEvent(false);
+ this.receiveNow = new ManualResetEvent(false);
+ this.sendDone = new ManualResetEvent(false);
+ this.connectionState = false;
+ this.checkConnection = new AutoResetEvent(false);
+ this.logThreadInitialized = new ManualResetEvent(false);
+ this.terminateLogThread = new ManualResetEvent(false);
+ this.logQueue = new Queue();
+ this.logThread = null;
+ return;
+ }
+ else
+ {
+ throw new ArgumentException("timeout must not be negative.", "timeout");
+ }
+ }
+ else
+ {
+ throw new ArgumentException("baudRate must not be negative.", "baudRate");
+ }
+ }
+ else
+ {
+ throw new ArgumentException("portName must not be an empty string.");
+ }
+ }
+ else
+ {
+ throw new ArgumentNullException("portName");
+ }
+ }
+
+ ///
+ /// Initializing a new instance of the class.
+ ///
+ /// The communication (COM) port to use.
+ /// The baud rate (speed) to use.
+ /// The communication timeout in milliseconds.
+ public GsmPhone(int portNumber, int baudRate, int timeout) : this(string.Concat("COM", portNumber.ToString()), baudRate, timeout)
+ {
+ }
+
+ ///
+ /// AT+CNMA. Confirms reception of a new message (SMS-DELIVER or SMS-STATUS-REPORT) which is routed
+ /// directly to the TE. This acknowledgement command shall be used when "service" parameter
+ /// of the function equals 1.
+ ///
+ /// This sends a positive acknowledgement to the network.
+ public void AcknowledgeNewMessage()
+ {
+ lock (this)
+ {
+ this.AcknowledgeNewMessage(true);
+ }
+ }
+
+ ///
+ /// AT+CNMA. Confirms reception of a new message (SMS-DELIVER or SMS-STATUS-REPORT) which is routed
+ /// directly to the TE. This acknowledgement command shall be used when "service" parameter
+ /// of the function equals 1.
+ ///
+ /// Specifies whether the message was received correctly.
+ /// Setting this parameter to true, will send a positive (RP-ACK) acknowledgement to the network.
+ /// Setting this parameter to false, will send a negative (RP-ERROR) acknowledgement to the network.
+ ///
+ ///
+ /// If ME does not get acknowledgement within required time (network timeout), ME should send RP-ERROR to
+ /// the network. ME/TA shall automatically disable routing to TE.
+ /// If command is executed, but no acknowledgement is expected, or some other ME related error occurs,
+ /// a is raised.
+ ///
+ public void AcknowledgeNewMessage(bool ok)
+ {
+ byte num;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.ActivatePduMode();
+ string str = "AT+CNMA=";
+ if (ok)
+ {
+ num = 0;
+ }
+ else
+ {
+ num = 2;
+ }
+ string str1 = string.Concat(str, num);
+ this.ExecAndReceiveMultiple(str1);
+ }
+ }
+
+ ///
+ /// AT+CMGF. Activates the PDU mode. Device must support it or the call will fail.
+ ///
+ private void ActivatePduMode()
+ {
+ this.LogIt(LogLevel.Info, "Activating PDU mode...");
+ this.ExecAndReceiveMultiple("AT+CMGF=0");
+ }
+
+ ///
+ /// AT+CMGF. Activates the text mode. Device must support it or the call will fail.
+ ///
+ private void ActivateTextMode()
+ {
+ this.LogIt(LogLevel.Info, "Activating text mode...");
+ this.ExecAndReceiveMultiple("AT+CMGF=1");
+ }
+
+ private void AsyncCallback(IAsyncResult ar)
+ {
+ AsyncResult asyncResult = (AsyncResult)ar;
+ if (asyncResult.AsyncDelegate as MessageReceivedEventHandler == null)
+ {
+ if (asyncResult.AsyncDelegate as EventHandler == null)
+ {
+ if (asyncResult.AsyncDelegate as ProgressEventHandler == null)
+ {
+ this.LogIt(LogLevel.Warning, string.Concat("AsyncCallback got unknown delegate: ", asyncResult.AsyncDelegate.GetType().ToString()));
+ return;
+ }
+ else
+ {
+ ProgressEventHandler asyncDelegate = (ProgressEventHandler)asyncResult.AsyncDelegate;
+ asyncDelegate.EndInvoke(ar);
+ return;
+ }
+ }
+ else
+ {
+ this.LogIt(LogLevel.Info, "Ending async EventHandler call");
+ EventHandler eventHandler = (EventHandler)asyncResult.AsyncDelegate;
+ eventHandler.EndInvoke(ar);
+ return;
+ }
+ }
+ else
+ {
+ this.LogIt(LogLevel.Info, "Ending async MessageReceivedEventHandler call");
+ MessageReceivedEventHandler messageReceivedEventHandler = (MessageReceivedEventHandler)asyncResult.AsyncDelegate;
+ messageReceivedEventHandler.EndInvoke(ar);
+ return;
+ }
+ }
+
+ private void CheckConnection()
+ {
+ if (Monitor.TryEnter(this))
+ {
+ try
+ {
+ bool flag = this.IsConnectedInternal();
+ this.SetNewConnectionState(flag);
+ }
+ finally
+ {
+ Monitor.Exit(this);
+ }
+ return;
+ }
+ else
+ {
+ this.LogIt(LogLevel.Verbose, "Object locked - connection check not performed.");
+ return;
+ }
+ }
+
+ ///
+ /// Closes the connection to the device.
+ ///
+ /// You can check the current connection state with the method.
+ ///
+ ///
+ ///
+ /// Port not open.
+ public void Close()
+ {
+ lock (this)
+ {
+ if (this.IsOpen())
+ {
+ this.TerminateCommThread();
+ try
+ {
+ this.ClosePort();
+ }
+ catch (Exception exception1)
+ {
+ Exception exception = exception1;
+ this.LogIt(LogLevel.Warning, "Closing the port failed. The exeption will not be rethrown to allow proper shutdown.");
+ this.LogIt(LogLevel.Warning, "Error details:");
+ this.LogItShow(LogLevel.Warning, exception.ToString(), "");
+ }
+ this.TerminateLogThread();
+ }
+ else
+ {
+ throw new InvalidOperationException("Port not open.");
+ }
+ }
+ }
+
+ private void ClosePort()
+ {
+ if (!this.port.IsOpen)
+ {
+ this.LogIt(LogLevel.Warning, "Attempted to close a closed serial connection. Ignored.");
+ }
+ else
+ {
+ this.LogIt(LogLevel.Info, "Closing serial connection.");
+ this.port.Close();
+ this.port.DataReceived -= new SerialDataReceivedEventHandler(this.port_DataReceived);
+ if (this.connectionState)
+ {
+ this.connectionState = false;
+ this.OnPhoneDisconnected();
+ return;
+ }
+ }
+ }
+
+ private void CommThread()
+ {
+ this.LogIt(LogLevel.Info, "Communication thread started.");
+ System.Timers.Timer timer = new System.Timers.Timer((double)this.commThreadCheckDelay);
+ timer.Elapsed += new ElapsedEventHandler(this.connectionTimer_Elapsed);
+ timer.AutoReset = false;
+ timer.Start();
+ object[] objArray = new object[1];
+ objArray[0] = this.commThreadCheckDelay;
+ this.LogIt(LogLevel.Info, "Connection to phone will be checked every {0} ms.", objArray);
+ WaitHandle[] waitHandleArray = new WaitHandle[4];
+ waitHandleArray[0] = this.terminateCommThread;
+ waitHandleArray[1] = this.sendNow;
+ waitHandleArray[2] = this.receiveNow;
+ waitHandleArray[3] = this.checkConnection;
+ WaitHandle[] waitHandleArray1 = waitHandleArray;
+ while (true)
+ {
+ int num = WaitHandle.WaitAny(waitHandleArray1);
+ if (num == 0)
+ {
+ break;
+ }
+ if (num != 1)
+ {
+ if (num != 2)
+ {
+ if (num == 3)
+ {
+ timer.Stop();
+ this.CheckConnection();
+ timer.Start();
+ }
+ }
+ else
+ {
+ if (this.CommThreadReceive())
+ {
+ timer.Stop();
+ this.checkConnection.Reset();
+ timer.Start();
+ }
+ }
+ }
+ else
+ {
+ string str = this.dataToSend;
+ this.sendNow.Reset();
+ this.inputQueue.Clear();
+ this.dataReceived.Reset();
+ try
+ {
+ this.SendInternal(str, true);
+ }
+ catch (Exception exception1)
+ {
+ Exception exception = exception1;
+ this.LogIt(LogLevel.Error, "Error while sending data to the phone.");
+ this.LogIt(LogLevel.Error, "Error details:");
+ this.LogIt(LogLevel.Error, exception.ToString());
+ }
+ this.sendDone.Set();
+ }
+ }
+ this.LogIt(LogLevel.Info, "Communication thread is terminating.");
+ if (!this.terminateCommThread.WaitOne(0, false))
+ {
+ this.LogIt(LogLevel.Warning, "Communication thread terminates without a stop signal!");
+ }
+ timer.Stop();
+ timer.Dispose();
+ this.checkConnection.Reset();
+ this.receiveNow.Reset();
+ this.dataReceived.Reset();
+ this.noData.Reset();
+ this.inputQueue.Clear();
+ this.sendNow.Reset();
+ this.sendDone.Reset();
+ this.dataToSend = string.Empty;
+ }
+
+ private bool CommThreadReceive()
+ {
+ bool flag;
+ string str = null;
+ this.receiveNow.Reset();
+ this.noData.Reset();
+ bool flag1 = false;
+ MessageIndicationHandlers messageIndicationHandler = new MessageIndicationHandlers();
+ StringBuilder stringBuilder = new StringBuilder();
+ do
+ {
+ flag = false;
+ try
+ {
+ if (this.ReceiveInternal(out str))
+ {
+ stringBuilder.Append(str);
+ flag = true;
+ }
+ }
+ catch (Exception exception1)
+ {
+ Exception exception = exception1;
+ this.LogIt(LogLevel.Error, "Error while receiving data from the phone.");
+ this.LogIt(LogLevel.Error, "Error details:");
+ this.LogIt(LogLevel.Error, exception.ToString());
+ stringBuilder = new StringBuilder();
+ flag = false;
+ break;
+ }
+ try
+ {
+ if (!flag && messageIndicationHandler.IsIncompleteUnsolicitedMessage(stringBuilder.ToString()))
+ {
+ this.LogIt(LogLevel.Info, "Incomplete unsolicited message found, reading on after sleep.");
+ Thread.Sleep(this.timeout);
+ flag = true;
+ }
+ }
+ catch (Exception exception3)
+ {
+ Exception exception2 = exception3;
+ this.LogIt(LogLevel.Error, "Error while checking received data for unsolicited messages.");
+ this.LogIt(LogLevel.Error, "Received data was:");
+ this.LogItShow(LogLevel.Error, stringBuilder.ToString(), ">> ");
+ this.LogIt(LogLevel.Error, "This data will not be processed further.");
+ this.LogIt(LogLevel.Error, "Error details:");
+ this.LogIt(LogLevel.Error, exception2.ToString());
+ stringBuilder = new StringBuilder();
+ flag = false;
+ }
+ }
+ while (flag);
+ if (stringBuilder.Length <= 0)
+ {
+ this.noData.Set();
+ flag1 = false;
+ }
+ else
+ {
+ this.inputQueue.Enqueue(stringBuilder.ToString());
+ string str1 = this.MakeQueueString(this.inputQueue);
+ if (this.HandleUnsolicitedMessages(ref str1))
+ {
+ this.inputQueue.Clear();
+ this.inputQueue.Enqueue(str1);
+ }
+ this.dataReceived.Set();
+ flag1 = true;
+ }
+ return flag1;
+ }
+
+ private void connectionTimer_Elapsed(object sender, ElapsedEventArgs e)
+ {
+ this.checkConnection.Set();
+ }
+
+ private void CreateCommThread()
+ {
+ if (!this.IsCommThreadRunning())
+ {
+ this.terminateCommThread.Reset();
+ this.commThread = new Thread(new ThreadStart(this.CommThread));
+ this.commThread.Name = "GsmPhone comm thread";
+ this.commThread.Start();
+ return;
+ }
+ else
+ {
+ this.LogIt(LogLevel.Warning, "Comm thread already created, ignoring call to CreateCommThread.");
+ return;
+ }
+ }
+
+ private void CreateLogThread()
+ {
+ if (this.logThread == null || !this.logThread.IsAlive)
+ {
+ this.logThreadInitialized.Reset();
+ this.terminateLogThread.Reset();
+ this.logThread = new Thread(new ThreadStart(this.LogThread));
+ this.logThread.Name = "GsmPhone log thread";
+ this.logThread.Start();
+ this.logThreadInitialized.WaitOne();
+ this.LogIt(LogLevel.Info, "Log thread started.");
+ return;
+ }
+ else
+ {
+ this.LogIt(LogLevel.Warning, "Log thread already created, ignoring call to CreateLogThread.");
+ return;
+ }
+ }
+
+ ///
+ /// Decodes a data stream with phonebook entries into objects.
+ ///
+ /// The entries to decode
+ /// The string the lines start with
+ private PhonebookEntry[] DecodePhonebookStream(string input, string prefix)
+ {
+ this.LogIt(LogLevel.Info, "Decoding phonebook entries...");
+ ArrayList arrayLists = new ArrayList();
+ Regex regex = new Regex(string.Concat(Regex.Escape(prefix), "(\\d+),\"(.+)\",(\\d+),\"(.+)\".*\\r\\n"));
+ for (Match i = regex.Match(input); i.Success; i = i.NextMatch())
+ {
+ int num = int.Parse(i.Groups[1].Value);
+ string value = i.Groups[2].Value;
+ int num1 = int.Parse(i.Groups[3].Value);
+ string str = i.Groups[4].Value;
+ arrayLists.Add(new PhonebookEntry(num, value, num1, str));
+ string[] strArrays = new string[9];
+ strArrays[0] = "Entry: index=";
+ strArrays[1] = num.ToString();
+ strArrays[2] = ", number=\"";
+ strArrays[3] = value;
+ strArrays[4] = "\", type=";
+ strArrays[5] = num1.ToString();
+ strArrays[6] = ", text=\"";
+ strArrays[7] = str;
+ strArrays[8] = "\"";
+ this.LogIt(LogLevel.Info, string.Concat(strArrays));
+ }
+ if (arrayLists.Count == 1)
+ {
+ this.LogIt(LogLevel.Info, "1 entry decoded.");
+ }
+ else
+ {
+ int count = arrayLists.Count;
+ this.LogIt(LogLevel.Info, string.Concat(count.ToString(), " entries decoded."));
+ }
+ PhonebookEntry[] phonebookEntryArray = new PhonebookEntry[arrayLists.Count];
+ arrayLists.CopyTo(phonebookEntryArray, 0);
+ return phonebookEntryArray;
+ }
+
+ ///
+ /// AT+CMGD. Deletes the specified SMS message from the current read/delete storage.
+ ///
+ /// The index of the message to delete.
+ public void DeleteMessage(int index)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, string.Concat("Deleting message with index ", index.ToString(), "..."));
+ this.ExecAndReceiveMultiple(string.Concat("AT+CMGD=", index.ToString()));
+ }
+ }
+
+ ///
+ /// AT+CMGD. Deletes the specified SMS message from the current read/delete storage.
+ ///
+ /// The index of the message to delete.
+ /// The delete flag, this controls the behaviour of the delete command.
+ public void DeleteMessage(int index, DeleteFlag delflag)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ string[] str = new string[5];
+ str[0] = "Deleting message with index ";
+ str[1] = index.ToString();
+ str[2] = ", using delflag ";
+ str[3] = delflag.ToString();
+ str[4] = "...";
+ this.LogIt(LogLevel.Info, string.Concat(str));
+ int num = delflag;
+ string str1 = string.Concat("AT+CMGD=", index.ToString(), ",", num.ToString());
+ this.ExecAndReceiveMultiple(str1);
+ }
+ }
+
+ ///
+ /// AT+CPBW. Deletes a phonebook entry.
+ ///
+ /// The index of the entry to delete.
+ /// In this case it does not matter whether the specified index is valid.
+ /// If the entry does not exist, no error is returned.
+ public void DeletePhonebookEntry(int index)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, string.Concat("Deleting phonebook entry ", index.ToString(), "..."));
+ this.ExecAndReceiveMultiple(string.Concat("AT+CPBW=", index.ToString()));
+ }
+ }
+
+ private bool DispatchLog()
+ {
+ LoglineAddedEventArgs loglineAddedEventArg = null;
+ lock (this.logQueue)
+ {
+ if (this.logQueue.Count > 0)
+ {
+ loglineAddedEventArg = (LoglineAddedEventArgs)this.logQueue.Dequeue();
+ }
+ }
+ if (loglineAddedEventArg == null)
+ {
+ return false;
+ }
+ else
+ {
+ try
+ {
+ if (this.LoglineAdded != null)
+ {
+ this.LoglineAdded(this, loglineAddedEventArg);
+ }
+ }
+ catch (Exception exception)
+ {
+ }
+ return true;
+ }
+ }
+
+ ///
+ /// AT+CPIN. Enters a password at the phone which is necessary before it can operated.
+ ///
+ /// The SIM PIN, SIM PUK or other password required.
+ /// Get the current PIN status with to check
+ /// whether a password must be entered.
+ public void EnterPin(string pin)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ object[] objArray = new object[1];
+ objArray[0] = pin;
+ this.LogIt(LogLevel.Info, "Entering PIN...", objArray);
+ this.logEnabled = false;
+ try
+ {
+ string str = string.Format("AT+CPIN=\"{0}\"", pin);
+ this.ExecAndReceiveMultiple(str);
+ }
+ finally
+ {
+ this.logEnabled = true;
+ }
+ }
+ }
+
+ private string ExecCommandInternal(string command, string receiveErrorMessage)
+ {
+ string str = null;
+ string str1 = string.Concat(command, "\r");
+ this.receiveNow.Reset();
+ this.SendInternal(str1, false);
+ StringBuilder stringBuilder = new StringBuilder();
+ while (this.receiveNow.WaitOne(this.timeout, false))
+ {
+ this.receiveNow.Reset();
+ this.ReceiveInternal(out str);
+ stringBuilder.Append(str);
+ }
+ string str2 = stringBuilder.ToString();
+ if (str2.Length != 0)
+ {
+ if (this.IsSuccess(str2))
+ {
+ if (str2.EndsWith("\r\nOK\r\n"))
+ {
+ str2 = str2.Remove(str2.LastIndexOf("\r\nOK\r\n"), "\r\nOK\r\n".Length);
+ }
+ if (str2.StartsWith(str1))
+ {
+ str2 = str2.Substring(str1.Length);
+ }
+ return str2;
+ }
+ else
+ {
+ this.HandleCommError(str2);
+ return null;
+ }
+ }
+ else
+ {
+ this.HandleRecvError(str2, receiveErrorMessage);
+ return null;
+ }
+ }
+
+ ///
+ /// AT+CPBF. Searches for the specified text in the phonebook.
+ ///
+ /// The text to find.
+ /// An array of objects containing
+ /// the specified text
+ public PhonebookEntry[] FindPhonebookEntries(string findText)
+ {
+ PhonebookEntry[] phonebookEntryArray;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, string.Concat("Searching phonebook entry \"", findText, "\"..."));
+ string str = string.Concat("AT+CPBF=\"", findText, "\"");
+ string str1 = this.ExecAndReceiveMultiple(str);
+ phonebookEntryArray = this.DecodePhonebookStream(str1, "+CPBF: ");
+ }
+ return phonebookEntryArray;
+ }
+
+ ///
+ /// AT+CBC. Gets the ME battery charging status and charge level.
+ ///
+ /// A object containing the battery details.
+ public BatteryChargeInfo GetBatteryCharge()
+ {
+ BatteryChargeInfo batteryChargeInfo;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting battery charge...");
+ string str = this.ExecAndReceiveMultiple("AT+CBC");
+ Regex regex = new Regex("\\+CBC: (\\d+),(\\d+)");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.HandleCommError(str);
+ batteryChargeInfo = null;
+ }
+ else
+ {
+ int num = int.Parse(match.Groups[1].Value);
+ int num1 = int.Parse(match.Groups[2].Value);
+ this.LogIt(LogLevel.Info, string.Concat("Battery charging status = ", num.ToString()));
+ this.LogIt(LogLevel.Info, string.Concat("Battery charge level = ", num1.ToString()));
+ BatteryChargeInfo batteryChargeInfo1 = new BatteryChargeInfo(num, num1);
+ batteryChargeInfo = batteryChargeInfo1;
+ }
+ }
+ return batteryChargeInfo;
+ }
+
+ ///
+ /// AT+CSCS. Retrives the currently selected character set.
+ ///
+ /// The current character set.
+ ///
+ ///
+ ///
+ ///
+ public string GetCurrentCharacterSet()
+ {
+ string empty;
+ string str;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Retrieving current character set...");
+ string str1 = this.ExecAndReceiveMultiple("AT+CSCS?");
+ Regex regex = new Regex("\\+CSCS: \"([^\"]+)\"");
+ Match match = regex.Match(str1);
+ if (!match.Success)
+ {
+ empty = string.Empty;
+ this.HandleCommError(str1);
+ }
+ else
+ {
+ empty = match.Groups[1].Value;
+ }
+ this.LogIt(LogLevel.Info, string.Concat("Current character set is \"", empty, "\"."));
+ str = empty;
+ }
+ return str;
+ }
+
+ ///
+ /// AT+CSMS. Gets the supported message types along with the current service setting.
+ ///
+ /// Specifies the compatibility level of the SMS AT commands.
+ /// The requirement of service setting 1 depends on specific commands.
+ ///
+ /// ME supports mobile terminated messages
+ /// ME supports mobile originated messages
+ /// ME supports broadcast type messages
+ public void GetCurrentMessageService(out int service, out int mt, out int mo, out int bm)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ string str = this.ExecAndReceiveMultiple("AT+CSMS?");
+ Regex regex = new Regex("\\+CSMS: (\\d+),(\\d+),(\\d+),(\\d+)");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.HandleCommError(str);
+ throw new CommException("Unexpected response.", str);
+ }
+ else
+ {
+ service = int.Parse(match.Groups[1].Value);
+ mt = int.Parse(match.Groups[2].Value);
+ mo = int.Parse(match.Groups[3].Value);
+ bm = int.Parse(match.Groups[4].Value);
+ }
+ }
+ }
+
+ ///
+ /// AT+COPS. Gets the currently selected network operator.
+ ///
+ /// An object containing the data or null if there is no current operator.
+ public OperatorInfo GetCurrentOperator()
+ {
+ OperatorInfo operatorInfo;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting current operator...");
+ string str = this.ExecAndReceiveMultiple("AT+COPS?");
+ Regex regex = new Regex("\\+COPS: (\\d+)(?:,(\\d+),\"(.+)\")?(?:,(.+))?");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.HandleCommError(str);
+ throw new CommException("Unexpected response.", str);
+ }
+ else
+ {
+ int.Parse(match.Groups[1].Value);
+ if (match.Groups.Count <= 1)
+ {
+ this.LogIt(LogLevel.Info, "There is no operator currently selected!");
+ operatorInfo = null;
+ }
+ else
+ {
+ int num = int.Parse(match.Groups[2].Value);
+ string value = match.Groups[3].Value;
+ string empty = string.Empty;
+ if (match.Groups.Count > 3)
+ {
+ empty = match.Groups[4].Value;
+ }
+ object[] objArray = new object[3];
+ objArray[0] = num;
+ objArray[1] = value;
+ objArray[2] = empty;
+ this.LogIt(LogLevel.Info, "format={0}, oper=\"{1}\", act=\"{2}\"", objArray);
+ if (Enum.IsDefined(typeof(OperatorFormat), num))
+ {
+ OperatorFormat operatorFormat = (OperatorFormat)Enum.Parse(typeof(OperatorFormat), num.ToString());
+ OperatorInfo operatorInfo1 = new OperatorInfo(operatorFormat, value, empty);
+ operatorInfo = operatorInfo1;
+ }
+ else
+ {
+ throw new CommException(string.Concat("Unknown operator format ", num.ToString()), str);
+ }
+ }
+ }
+ }
+ return operatorInfo;
+ }
+
+ ///
+ /// AT+CNMI. Gets the current message notification settings.
+ ///
+ /// A structure containing the detailed settings.
+ public MessageIndicationSettings GetMessageIndications()
+ {
+ MessageIndicationSettings messageIndicationSetting;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting current message indications...");
+ string str = this.ExecAndReceiveMultiple("AT+CNMI?");
+ Regex regex = new Regex("\\+CNMI: (\\d+),(\\d+),(\\d+),(\\d+),(\\d+)");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.HandleCommError(str);
+ throw new CommException("Unexpected response.", str);
+ }
+ else
+ {
+ MessageIndicationSettings messageIndicationSetting1 = new MessageIndicationSettings();
+ messageIndicationSetting1.Mode = int.Parse(match.Groups[1].Value);
+ messageIndicationSetting1.DeliverStyle = int.Parse(match.Groups[2].Value);
+ messageIndicationSetting1.CellBroadcastStyle = int.Parse(match.Groups[3].Value);
+ messageIndicationSetting1.StatusReportStyle = int.Parse(match.Groups[4].Value);
+ messageIndicationSetting1.BufferSetting = int.Parse(match.Groups[5].Value);
+ object[] mode = new object[5];
+ mode[0] = messageIndicationSetting1.Mode;
+ mode[1] = messageIndicationSetting1.DeliverStyle;
+ mode[2] = messageIndicationSetting1.CellBroadcastStyle;
+ mode[3] = messageIndicationSetting1.StatusReportStyle;
+ mode[4] = messageIndicationSetting1.BufferSetting;
+ this.LogIt(LogLevel.Info, string.Format("mode={0:g}, mt={1:g}, bm={2:g}, ds={3:g}, bfr={4:g}", mode));
+ messageIndicationSetting = messageIndicationSetting1;
+ }
+ }
+ return messageIndicationSetting;
+ }
+
+ ///
+ /// Returns the message service error code in the input string.
+ ///
+ /// The data received
+ /// The error code
+ /// Use the method to check if the string
+ /// contains a message service error message.
+ /// Input string does not contain a message service error code
+ private int GetMessageServiceErrorCode(string input)
+ {
+ Regex regex = new Regex("\\r\\n\\+CMS ERROR: (\\d+)\\r\\n");
+ Match match = regex.Match(input);
+ if (!match.Success || match.Groups[1].Captures.Count <= 0)
+ {
+ throw new ArgumentException("The input string does not contain a message service error code.");
+ }
+ else
+ {
+ return int.Parse(match.Groups[1].Captures[0].ToString());
+ }
+ }
+
+ ///
+ /// AT+CPMS. Gets the supported message storages.
+ ///
+ /// A object that contains details about the supported storages.
+ public MessageStorageInfo GetMessageStorages()
+ {
+ MessageStorageInfo messageStorageInfo;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ ArrayList arrayLists = new ArrayList();
+ this.LogIt(LogLevel.Info, "Enumerating supported message storages...");
+ string str = this.ExecAndReceiveMultiple("AT+CPMS=?");
+ int num = str.IndexOf("+CPMS: ");
+ if (num < 0)
+ {
+ this.HandleCommError(str);
+ }
+ else
+ {
+ str = str.Substring(num + "+CPMS: ".Length);
+ }
+ Regex regex = new Regex("\\((?:\"(\\w+)\"(?(?!\\)),))+\\)");
+ for (Match i = regex.Match(str); i.Success; i = i.NextMatch())
+ {
+ int count = i.Groups[1].Captures.Count;
+ string[] value = new string[count];
+ for (int j = 0; j < count; j++)
+ {
+ value[j] = i.Groups[1].Captures[j].Value;
+ }
+ arrayLists.Add(value);
+ }
+ }
+ return messageStorageInfo;
+ }
+
+ ///
+ /// Returns the mobile equipment error code in the input string.
+ ///
+ /// The data received
+ /// The mobile equipment error code
+ /// Use the method to check if the string
+ /// contains mobile equipment error message.
+ /// Input string does not contain a mobile equipment error code
+ private int GetMobileEquipmentErrorCode(string input)
+ {
+ Regex regex = new Regex("\\r\\n\\+CME ERROR: (\\d+)\\r\\n");
+ Match match = regex.Match(input);
+ if (!match.Success || match.Groups[1].Captures.Count <= 0)
+ {
+ throw new ArgumentException("The input string does not contain a mobile equipment error code.");
+ }
+ else
+ {
+ return int.Parse(match.Groups[1].Captures[0].ToString());
+ }
+ }
+
+ ///
+ /// AT+CMMS. Gets the current SMS batch mode setting.
+ ///
+ /// The current mode.
+ public MoreMessagesMode GetMoreMessagesToSend()
+ {
+ MoreMessagesMode moreMessagesMode;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting more messages mode...");
+ string str = string.Format("AT+CMMS?", new object[0]);
+ string str1 = this.ExecAndReceiveMultiple(str);
+ Regex regex = new Regex("\\+CMMS: (\\d+)");
+ Match match = regex.Match(str1);
+ if (!match.Success)
+ {
+ this.HandleCommError(str1);
+ throw new CommException("Unexpected response.", str1);
+ }
+ else
+ {
+ int num = int.Parse(match.Groups[1].Value);
+ object[] objArray = new object[1];
+ objArray[0] = num;
+ this.LogIt(LogLevel.Info, "mode=\"{0}\"", objArray);
+ if (Enum.IsDefined(typeof(MoreMessagesMode), num))
+ {
+ MoreMessagesMode moreMessagesMode1 = (MoreMessagesMode)Enum.Parse(typeof(MoreMessagesMode), num.ToString());
+ moreMessagesMode = moreMessagesMode1;
+ }
+ else
+ {
+ throw new CommException(string.Concat("Unknown more messages mode ", num.ToString(), "."), str1);
+ }
+ }
+ }
+ return moreMessagesMode;
+ }
+
+ ///
+ /// AT+COPS. Determines the current mode to select a network operator.
+ ///
+ /// The current mode, see for possible values.
+ public int GetOperatorSelectionMode()
+ {
+ int num;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting current operator selection mode...");
+ string str = this.ExecAndReceiveMultiple("AT+COPS?");
+ Regex regex = new Regex("\\+COPS: (\\d+)(?:,(\\d+),\"(.+)\")?(?:,(.+))?");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.HandleCommError(str);
+ throw new CommException("Unexpected response.", str);
+ }
+ else
+ {
+ int num1 = int.Parse(match.Groups[1].Value);
+ object[] objArray = new object[1];
+ objArray[0] = num1.ToString();
+ this.LogIt(LogLevel.Info, "Current mode is {0}.", objArray);
+ num = num1;
+ }
+ }
+ return num;
+ }
+
+ ///
+ /// AT+CPBS. Gets the memory status of the currently selected phonebook storage.
+ ///
+ /// The memory status of the currently selected storage.
+ public MemoryStatusWithStorage GetPhonebookMemoryStatus()
+ {
+ MemoryStatusWithStorage memoryStatusWithStorage;
+ int used;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting phonebook memory status...");
+ string str = this.ExecAndReceiveMultiple("AT+CPBS?");
+ MemoryStatusWithStorage memoryStatusWithStorage1 = this.ParsePhonebookMemoryStatus(str);
+ if (memoryStatusWithStorage1.Total > 0)
+ {
+ used = (int)((double)memoryStatusWithStorage1.Used / (double)memoryStatusWithStorage1.Total * 100);
+ }
+ else
+ {
+ used = 0;
+ }
+ int num = used;
+ object[] storage = new object[4];
+ storage[0] = memoryStatusWithStorage1.Storage;
+ storage[1] = memoryStatusWithStorage1.Used;
+ storage[2] = memoryStatusWithStorage1.Total;
+ storage[3] = num;
+ this.LogIt(LogLevel.Info, string.Format("Memory status: storage=\"{0}\" {1}/{2} ({3}% used)", storage));
+ memoryStatusWithStorage = memoryStatusWithStorage1;
+ }
+ return memoryStatusWithStorage;
+ }
+
+ ///
+ /// AT+CPBR. Queries the size of the currently selected phonebook.
+ ///
+ /// Receives the lower bound of the phonebook
+ /// Receives the upper bound of the phonebook
+ /// Receives the maximum number length, 0 if unknown
+ /// Receives the maximum text length, 0 if unknown
+ public void GetPhonebookSize(out int lowerBound, out int upperBound, out int nLength, out int tLength)
+ {
+ int num;
+ int num1;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting phonebook size...");
+ string str = this.ExecAndReceiveMultiple("AT+CPBR=?");
+ Regex regex = new Regex("\\+CPBR: \\((\\d+)-(\\d+)\\)\\,(\\d*),(\\d*)");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.HandleCommError(str);
+ }
+ lowerBound = int.Parse(match.Groups[1].Value);
+ upperBound = int.Parse(match.Groups[2].Value);
+ int& numPointer = nLength;
+ if (match.Groups[3].Value != "")
+ {
+ num = int.Parse(match.Groups[3].Value);
+ }
+ else
+ {
+ num = 0;
+ }
+ *(numPointer) = num;
+ int& numPointer1 = tLength;
+ if (match.Groups[4].Value != "")
+ {
+ num1 = int.Parse(match.Groups[4].Value);
+ }
+ else
+ {
+ num1 = 0;
+ }
+ *(numPointer1) = num1;
+ string[] strArrays = new string[8];
+ strArrays[0] = "lowerBound=";
+ strArrays[1] = lowerBound.ToString();
+ strArrays[2] = ", upperBound=";
+ strArrays[3] = upperBound.ToString();
+ strArrays[4] = ", nLength=";
+ strArrays[5] = nLength.ToString();
+ strArrays[6] = ", tLength=";
+ strArrays[7] = tLength.ToString();
+ this.LogIt(LogLevel.Info, string.Concat(strArrays));
+ }
+ }
+
+ ///
+ /// AT+CPBS. Gets the supported phonebook storages.
+ ///
+ /// An array of the supported storages
+ public string[] GetPhonebookStorages()
+ {
+ string[] strArrays;
+ string str;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Enumerating supported storages...");
+ string str1 = this.ExecAndReceiveMultiple("AT+CPBS=?");
+ string[] value = null;
+ Regex regex = new Regex("\\+CPBS: \\((?:\"(\\w+)\"(?(?!\\)),))+\\)");
+ Match match = regex.Match(str1);
+ if (!match.Success)
+ {
+ this.HandleCommError(str1);
+ }
+ else
+ {
+ int count = match.Groups[1].Captures.Count;
+ value = new string[count];
+ for (int i = 0; i < count; i++)
+ {
+ value[i] = match.Groups[1].Captures[i].Value;
+ }
+ }
+ string empty = string.Empty;
+ int num = 0;
+ while (num < (int)value.Length)
+ {
+ string str2 = empty;
+ if (empty == string.Empty)
+ {
+ str = "";
+ }
+ else
+ {
+ str = ", ";
+ }
+ empty = string.Concat(str2, str, value[num]);
+ num++;
+ }
+ this.LogIt(LogLevel.Info, string.Concat("Supported storages: ", empty));
+ strArrays = value;
+ }
+ return strArrays;
+ }
+
+ ///
+ /// AT+CPIN. Returns a value indicating whether some password must be entered at the phone or not.
+ ///
+ /// The current PIN status as one of the values.
+ public PinStatus GetPinStatus()
+ {
+ PinStatus status;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting PIN status...");
+ string str = string.Format("AT+CPIN?", new object[0]);
+ string str1 = this.ExecAndReceiveMultiple(str);
+ Regex regex = new Regex("\\+CPIN: (.+)\\r\\n");
+ Match match = regex.Match(str1);
+ if (!match.Success)
+ {
+ this.HandleCommError(str1);
+ throw new CommException("Unexpected response.", str1);
+ }
+ else
+ {
+ string value = match.Groups[1].Value;
+ object[] objArray = new object[1];
+ objArray[0] = value;
+ this.LogIt(LogLevel.Info, "status=\"{0}\"", objArray);
+ status = this.MapPinStatusStringToStatus(value);
+ }
+ }
+ return status;
+ }
+
+ ///
+ /// Enables access to the protocol level of the current connection.
+ ///
+ /// An object that sends and receives data at the protocol level.
+ /// This method enables execution of custom commands that are not directly supported. It also disables execution of background
+ /// operations that would usually take place, such as checking whether the phone is still connected.
+ /// The method must be called as soon as execution of the custom commands is completed,
+ /// and allows for normal operations to continue. Execution of other commands besides from is not allowed
+ /// until is called.
+ ///
+ ///
+ public IProtocol GetProtocol()
+ {
+ Monitor.Enter(this);
+ return this;
+ }
+
+ ///
+ /// AT+CSQ. Gets the signal quality as calculated by the ME.
+ ///
+ /// A object containing the signal details.
+ public SignalQualityInfo GetSignalQuality()
+ {
+ SignalQualityInfo signalQualityInfo;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting signal quality...");
+ string str = this.ExecAndReceiveMultiple("AT+CSQ");
+ Regex regex = new Regex("\\+CSQ: (\\d+),(\\d+)");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.HandleCommError(str);
+ signalQualityInfo = null;
+ }
+ else
+ {
+ int num = int.Parse(match.Groups[1].Value);
+ int num1 = int.Parse(match.Groups[2].Value);
+ this.LogIt(LogLevel.Info, string.Concat("Signal strength = ", num.ToString()));
+ this.LogIt(LogLevel.Info, string.Concat("Bit error rate = ", num1.ToString()));
+ SignalQualityInfo signalQualityInfo1 = new SignalQualityInfo(num, num1);
+ signalQualityInfo = signalQualityInfo1;
+ }
+ }
+ return signalQualityInfo;
+ }
+
+ ///
+ /// AT+CSCA. Gets the SMS Service Center Address.
+ ///
+ /// The current SMSC address
+ /// This command returns the SMSC address, through which SMS messages are transmitted.
+ /// In text mode, this setting is used by SMS sending and SMS writing commands. In PDU mode, this setting is
+ /// used by the same commands, but only when the length of the SMSC address coded into the PDU data equals
+ /// zero.
+ public AddressData GetSmscAddress()
+ {
+ AddressData addressDatum;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting SMSC address...");
+ string str = "AT+CSCA?";
+ string str1 = this.ExecAndReceiveMultiple(str);
+ Regex regex = new Regex("\\+CSCA: \"(.*)\",(\\d+)");
+ Match match = regex.Match(str1);
+ if (!match.Success)
+ {
+ this.HandleCommError(str1);
+ throw new CommException("Unexpected response.", str1);
+ }
+ else
+ {
+ string value = match.Groups[1].Value;
+ int num = int.Parse(match.Groups[2].Value);
+ object[] objArray = new object[2];
+ objArray[0] = value;
+ objArray[1] = num.ToString();
+ this.LogIt(LogLevel.Info, "address=\"{0}\", typeOfAddress={1}", objArray);
+ AddressData addressDatum1 = new AddressData(value, num);
+ addressDatum = addressDatum1;
+ }
+ }
+ return addressDatum;
+ }
+
+ ///
+ /// AT+CNUM. Returns the MSISDNs related to the subscriber.
+ ///
+ /// An array of objects with one for each MSISDN
+ /// (Mobile Subscriber ISDN Number), depending on the services subscribed.
+ ///
+ /// This information can be stored in the SIM/UICC or in the MT.
+ /// If the command is supported by the phone but no number can be retrieved,
+ /// an empty array is returned.
+ ///
+ public SubscriberInfo[] GetSubscriberNumbers()
+ {
+ SubscriberInfo[] subscriberInfoArray;
+ string empty;
+ int num;
+ int num1;
+ int num2;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting subscriber numbers...");
+ string str = this.ExecAndReceiveMultiple("AT+CNUM");
+ Regex regex = new Regex("\\+CNUM: (.*),\"(.*)\",(\\d+)(?:,(\\d+),(\\d+)(?:,(\\d+))?)?(?:\\r\\n)?");
+ Match match = regex.Match(str);
+ List subscriberInfos = new List();
+ while (match.Success)
+ {
+ if (match.Groups[1].Captures.Count <= 0 || match.Groups[1].Length <= 0)
+ {
+ empty = string.Empty;
+ }
+ else
+ {
+ empty = match.Groups[1].Value;
+ }
+ string str1 = empty;
+ string value = match.Groups[2].Value;
+ int num3 = int.Parse(match.Groups[3].Value);
+ if (match.Groups[4].Captures.Count <= 0 || match.Groups[4].Length <= 0)
+ {
+ num = -1;
+ }
+ else
+ {
+ num = int.Parse(match.Groups[4].Value);
+ }
+ int num4 = num;
+ if (match.Groups[5].Captures.Count <= 0 || match.Groups[5].Length <= 0)
+ {
+ num1 = -1;
+ }
+ else
+ {
+ num1 = int.Parse(match.Groups[5].Value);
+ }
+ int num5 = num1;
+ if (match.Groups[6].Captures.Count <= 0 || match.Groups[6].Length <= 0)
+ {
+ num2 = -1;
+ }
+ else
+ {
+ num2 = int.Parse(match.Groups[6].Value);
+ }
+ int num6 = num2;
+ object[] objArray = new object[6];
+ objArray[0] = str1;
+ objArray[1] = value;
+ objArray[2] = num3;
+ objArray[3] = num4;
+ objArray[4] = num5;
+ objArray[5] = num6;
+ this.LogIt(LogLevel.Info, "alpha=\"{0}\",number=\"{1}\",type={2},speed={3},service={4},itc={5}", objArray);
+ SubscriberInfo subscriberInfo = new SubscriberInfo(str1, value, num3, num4, num5, num6);
+ subscriberInfos.Add(subscriberInfo);
+ match = match.NextMatch();
+ }
+ SubscriberInfo[] subscriberInfoArray1 = new SubscriberInfo[subscriberInfos.Count];
+ subscriberInfos.CopyTo(subscriberInfoArray1);
+ subscriberInfoArray = subscriberInfoArray1;
+ }
+ return subscriberInfoArray;
+ }
+
+ ///
+ /// AT+CSCS. Retrieves the phone's supported character sets.
+ ///
+ /// A string array containing the supported character sets.
+ ///
+ ///
+ ///
+ ///
+ public string[] GetSupportedCharacterSets()
+ {
+ string[] strArrays;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Enumerating supported character sets...");
+ string str = this.ExecAndReceiveMultiple("AT+CSCS=?");
+ string[] value = null;
+ Regex regex = new Regex("\\+CSCS: \\((?:\"([^\"]+)\"(?(?!\\)),))+\\)");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.HandleCommError(str);
+ }
+ else
+ {
+ int count = match.Groups[1].Captures.Count;
+ value = new string[count];
+ for (int i = 0; i < count; i++)
+ {
+ value[i] = match.Groups[1].Captures[i].Value;
+ }
+ }
+ string str1 = this.MakeArrayString(value);
+ this.LogIt(LogLevel.Info, string.Concat("Supported character sets: ", str1));
+ strArrays = value;
+ }
+ return strArrays;
+ }
+
+ ///
+ /// AT+CNMI. Gets the supported new message indications from the phone.
+ ///
+ /// A object containing information about the supported
+ /// indications.
+ public MessageIndicationSupport GetSupportedIndications()
+ {
+ MessageIndicationSupport messageIndicationSupport;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Getting supported message indications...");
+ string str = this.ExecAndReceiveMultiple("AT+CNMI=?");
+ Regex regex = new Regex("\\+CNMI: \\(([\\d,-])+\\),\\(([\\d,-]+)\\),\\(([\\d,-]+)\\),\\(([\\d,-]+)\\),\\(([\\d,-]+)\\)");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.HandleCommError(str);
+ throw new CommException("Unexpected response.", str);
+ }
+ else
+ {
+ string empty = string.Empty;
+ string empty1 = string.Empty;
+ string str1 = string.Empty;
+ string empty2 = string.Empty;
+ string str2 = string.Empty;
+ foreach (Capture capture in match.Groups[1].Captures)
+ {
+ empty = string.Concat(empty, capture.Value);
+ }
+ foreach (Capture capture1 in match.Groups[2].Captures)
+ {
+ empty1 = string.Concat(empty1, capture1.Value);
+ }
+ foreach (Capture capture2 in match.Groups[3].Captures)
+ {
+ str1 = string.Concat(str1, capture2.Value);
+ }
+ foreach (Capture capture3 in match.Groups[4].Captures)
+ {
+ empty2 = string.Concat(empty2, capture3.Value);
+ }
+ foreach (Capture capture4 in match.Groups[5].Captures)
+ {
+ str2 = string.Concat(str2, capture4.Value);
+ }
+ object[] objArray = new object[5];
+ objArray[0] = empty;
+ objArray[1] = empty1;
+ objArray[2] = str1;
+ objArray[3] = empty2;
+ objArray[4] = str2;
+ this.LogIt(LogLevel.Info, "mode=\"{0}\", deliver=\"{1}\", cellBroadcast=\"{2}\", statusReport=\"{3}\", buffer=\"{4}\"", objArray);
+ MessageIndicationSupport messageIndicationSupport1 = new MessageIndicationSupport(empty, empty1, str1, empty2, str2);
+ messageIndicationSupport = messageIndicationSupport1;
+ }
+ }
+ return messageIndicationSupport;
+ }
+
+ ///
+ /// Executes the specified command and reads multiple times from the phone
+ /// until a specific pattern is detected in the response.
+ ///
+ /// The command to execute.
+ /// The regular expression pattern that the received data must match to stop
+ /// reading.
+ /// The response received.
+ ///
+ ///
+ ///
+ public string ExecAndReceiveAnything(string command, string pattern)
+ {
+ string str = string.Concat(command, "\r");
+ this.Send(str);
+ string str1 = this.ReceiveAnything(pattern);
+ if (str1.StartsWith(str))
+ {
+ str1 = str1.Substring(str.Length);
+ }
+ return str1;
+ }
+
+ /// Executes the specified command and reads multiple times from the phone
+ /// until one of the defined message termination patterns is detected in the response.
+ /// The command to execute.
+ /// The response received.
+ ///
+ ///
+ ///
+ public string ExecAndReceiveMultiple(string command)
+ {
+
+ string str = string.Concat(command, "\r");
+ this.Send(str);
+ string str1 = this.ReceiveMultiple();
+ if (str1.EndsWith("\r\nOK\r\n"))
+ {
+ str1 = str1.Remove(str1.LastIndexOf("\r\nOK\r\n"), "\r\nOK\r\n".Length);
+ }
+ if (str1.StartsWith(str))
+ {
+ str1 = str1.Substring(str.Length);
+ }
+ return str1;
+ }
+
+ /// Executes the specified command and reads a single response.
+ /// The command to execute.
+ /// The response received.
+ ///
+ /// This method returns whatever response comes in from the phone during a single read operation.
+ /// The response received may not be complete.
+ /// If you want to ensure that always complete responses are read, use instead.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public string ExecCommand(string command)
+ {
+ return this.ExecCommand(command, "No answer from phone.");
+ }
+
+ ///
+ /// Executes the specified command and reads a single response.
+ /// The command to execute.
+ /// The message text for the exception if no data is received.
+ /// The response received.
+ ///
+ /// This method returns whatever response comes in from the phone during a single read operation.
+ /// The response received may not be complete.
+ /// If you want to ensure that always complete responses are read, use instead.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public string ExecCommand(string command, string receiveErrorMessage)
+ {
+ string str = null;
+ string str1 = string.Concat(command, "\r");
+ this.Send(str1);
+ if (this.Receive(out str))
+ {
+ this.LogItShow(LogLevel.Verbose, str, ">> ");
+ if (this.IsSuccess(str))
+ {
+ if (str.EndsWith("\r\nOK\r\n"))
+ {
+ str = str.Remove(str.LastIndexOf("\r\nOK\r\n"), "\r\nOK\r\n".Length);
+ }
+ if (str.StartsWith(str1))
+ {
+ str = str.Substring(str1.Length);
+ }
+ return str;
+ }
+ else
+ {
+ this.HandleCommError(str);
+ return null;
+ }
+ }
+ else
+ {
+ this.HandleRecvError(str, receiveErrorMessage);
+ return null;
+ }
+ }
+
+ /// Receives raw string data.
+ /// The data received.
+ /// true if reception was successful, otherwise false.
+ ///
+ public bool GsmComm.GsmCommunication.IProtocol.Receive(out string input)
+ {
+ input = string.Empty;
+ if (!this.IsCommThreadRunning())
+ {
+ throw new InvalidOperationException("Communication thread is not running.");
+ }
+ else
+ {
+ WaitHandle[] waitHandleArray = new WaitHandle[2];
+ waitHandleArray[0] = this.dataReceived;
+ waitHandleArray[1] = this.noData;
+ WaitHandle[] waitHandleArray1 = waitHandleArray;
+ int num = WaitHandle.WaitAny(waitHandleArray1, 5000, false);
+ if (num == 0)
+ {
+ this.dataReceived.Reset();
+ if (this.inputQueue.Count <= 0)
+ {
+ this.LogIt(LogLevel.Warning, "Nothing in input queue");
+ }
+ else
+ {
+ while (this.inputQueue.Count > 0)
+ {
+ input = string.Concat(input, (string)this.inputQueue.Dequeue());
+ }
+ }
+ }
+ this.noData.Reset();
+ return input.Length > 0;
+ }
+ }
+
+ /// Reads multiple times from the phone until a specific pattern is detected in the response.
+ /// The response received.
+ /// The regular expression pattern that the received data must match to
+ /// stop reading. Can be an empty string if the pattern should not be checked.
+ ///
+ ///
+ ///
+ public string GsmComm.GsmCommunication.IProtocol.ReceiveAnything(string pattern)
+ {
+ string str = null;
+ string empty = string.Empty;
+ int tickCount = Environment.TickCount;
+ this.OnReceiveProgress(empty.Length);
+ int num = 0;
+ int num1 = 0;
+ while (!this.IsSuccess(empty) && !this.IsCommError(empty) && !this.IsMessageServiceError(empty) && !this.IsMobileEquipmentError(empty) && num < 6)
+ {
+ if (!this.Receive(out str))
+ {
+ num++;
+ if (num <= 1)
+ {
+ continue;
+ }
+ this.LogIt(LogLevel.Info, string.Concat("Waiting for response from phone (", num.ToString(), " empty read(s))."));
+ }
+ else
+ {
+ empty = string.Concat(empty, str);
+ num = 0;
+ num1++;
+ this.OnReceiveProgress(empty.Length);
+ if (pattern.Length <= 0 || !Regex.IsMatch(empty, pattern))
+ {
+ continue;
+ }
+ break;
+ }
+ }
+ int tickCount1 = Environment.TickCount - tickCount;
+ this.LogItShow(LogLevel.Verbose, empty, ">> ");
+ this.OnReceiveComplete(empty.Length);
+ if (num < 6)
+ {
+ if (tickCount1 > this.timeout)
+ {
+ object[] objArray = new object[2];
+ int length = empty.Length;
+ objArray[0] = length.ToString();
+ objArray[1] = tickCount1.ToString();
+ this.LogIt(LogLevel.Info, "{0} characters received after {1} ms.", objArray);
+ }
+ if (pattern.Length != 0 || this.IsSuccess(empty))
+ {
+ this.HandleUnsolicitedMessages(ref empty);
+ return empty;
+ }
+ else
+ {
+ this.HandleCommError(empty);
+ return string.Empty;
+ }
+ }
+ else
+ {
+ string[] strArrays = new string[5];
+ strArrays[0] = "Timeout after ";
+ strArrays[1] = num.ToString();
+ strArrays[2] = " empty reading attempts within ";
+ strArrays[3] = tickCount1.ToString();
+ strArrays[4] = " ms.";
+ this.LogIt(LogLevel.Error, string.Concat(strArrays));
+ throw new CommException(string.Concat("No data received from phone after waiting for ", tickCount1.ToString(), " ms."));
+ }
+ }
+
+ /// Reads multiple times from the phone until one of the defined
+ /// message termination patterns is detected in the response.
+ /// The response received.
+ ///
+ ///
+ ///
+ public string GsmComm.GsmCommunication.IProtocol.ReceiveMultiple()
+ {
+ return this.ReceiveAnything(string.Empty);
+ }
+
+ /// Sends raw string data.
+ /// The data to send.
+ ///
+ public void GsmComm.GsmCommunication.IProtocol.Send(string output)
+ {
+ if (!this.IsCommThreadRunning())
+ {
+ throw new InvalidOperationException("Communication thread is not running.");
+ }
+ else
+ {
+ this.dataToSend = output;
+ this.sendDone.Reset();
+ this.sendNow.Set();
+ this.sendDone.WaitOne();
+ return;
+ }
+ }
+
+ ///
+ /// Handles a communication error.
+ ///
+ /// The data received.
+ /// Call this function when communicating and the response is not a success response. This
+ /// function checks if the response contains an error message. In any case a
+ /// or an exception derived from it is thrown based on the type of error.
+ ///
+ /// Always thrown based on type of error.
+ private void HandleCommError(string input)
+ {
+ if (!this.IsCommError(input))
+ {
+ if (!this.IsMessageServiceError(input))
+ {
+ if (!this.IsMobileEquipmentError(input))
+ {
+ if (input.Length != 0)
+ {
+ this.LogIt(LogLevel.Error, "Failed. Unexpected response.");
+ this.LogIt(LogLevel.Error, "Received input:");
+ this.LogItShow(LogLevel.Error, input, "");
+ throw new CommException(string.Concat("Unexpected response received from phone:", Environment.NewLine, Environment.NewLine, input));
+ }
+ else
+ {
+ this.LogIt(LogLevel.Error, "Failed. No answer from phone.");
+ throw new CommException("No answer from phone.");
+ }
+ }
+ else
+ {
+ int mobileEquipmentErrorCode = this.GetMobileEquipmentErrorCode(input);
+ this.LogIt(LogLevel.Error, string.Concat("Failed. Phone reports mobile equipment (ME) error ", mobileEquipmentErrorCode.ToString(), "."));
+ this.LogItShow(LogLevel.Error, input, "");
+ throw new MobileEquipmentErrorException(string.Concat("Mobile equipment error ", mobileEquipmentErrorCode.ToString(), " occurred."), mobileEquipmentErrorCode, input);
+ }
+ }
+ else
+ {
+ int messageServiceErrorCode = this.GetMessageServiceErrorCode(input);
+ this.LogIt(LogLevel.Error, string.Concat("Failed. Phone reports message service (MS) error ", messageServiceErrorCode.ToString(), "."));
+ this.LogItShow(LogLevel.Error, input, "");
+ throw new MessageServiceErrorException(string.Concat("Message service error ", messageServiceErrorCode.ToString(), " occurred."), messageServiceErrorCode, input);
+ }
+ }
+ else
+ {
+ string str = "The phone reports an unspecified error. This typically happens when a command is not supported by the device, a command is not valid for the current state or if a parameter is incorrect.";
+ this.LogIt(LogLevel.Error, string.Concat("Failed. ", str, " The response received was: "));
+ this.LogItShow(LogLevel.Error, input, "");
+ throw new CommException(str, input);
+ }
+ }
+
+ private void HandleRecvError(string input, string userMessage)
+ {
+ if (input.Length <= 0)
+ {
+ this.LogIt(LogLevel.Error, "Failed. Receiving error.");
+ }
+ else
+ {
+ this.LogIt(LogLevel.Error, "Failed. Receiving error. Data until error:");
+ this.LogItShow(LogLevel.Error, input, "");
+ }
+ throw new CommException(userMessage);
+ }
+
+ private bool HandleUnsolicitedMessages(ref string bigInput)
+ {
+ string str = null;
+ MessageIndicationHandlers messageIndicationHandler = new MessageIndicationHandlers();
+ if (!messageIndicationHandler.IsUnsolicitedMessage(bigInput))
+ {
+ return false;
+ }
+ else
+ {
+ this.LogItShow(LogLevel.Verbose, bigInput, ">> ");
+ IMessageIndicationObject messageIndicationObject = messageIndicationHandler.HandleUnsolicitedMessage(ref bigInput, out str);
+ this.LogIt(LogLevel.Info, string.Concat("Unsolicited message: ", str));
+ this.OnMessageReceived(messageIndicationObject);
+ return true;
+ }
+ }
+
+ private bool IsCommError(string input)
+ {
+ return input.IndexOf("\r\nERROR\r\n") >= 0;
+ }
+
+ private bool IsCommThreadRunning()
+ {
+ if (this.commThread == null)
+ {
+ return false;
+ }
+ else
+ {
+ return this.commThread.IsAlive;
+ }
+ }
+
+ ///
+ /// Checks if there is a device connected and responsive.
+ ///
+ /// true if there is really a device connected and it responds to commands, false otherwise.
+ ///
+ /// You can use this function after opening the port with to verify that there is really a device connected
+ /// before processding.
+ ///
+ ///
+ ///
+ public bool IsConnected()
+ {
+ bool flag;
+ lock (this)
+ {
+ flag = this.connectionState;
+ }
+ return flag;
+ }
+
+ ///
+ /// AT. Checks if there is a device connected and responsive.
+ ///
+ /// true if there is really a device connected and it responds to commands, false otherwise.
+ ///
+ /// Bypasses the communication thread and does a direct send/receive.
+ ///
+ private bool IsConnectedInternal()
+ {
+ bool flag;
+ lock (this)
+ {
+ try
+ {
+ this.ExecCommandInternal("AT", "No phone connected.");
+ }
+ catch (Exception exception)
+ {
+ flag = false;
+ return flag;
+ }
+ flag = true;
+ }
+ return flag;
+ }
+
+ private bool IsMessageServiceError(string input)
+ {
+ return Regex.IsMatch(input, "\\r\\n\\+CMS ERROR: (\\d+)\\r\\n");
+ }
+
+ ///
+ /// Checks if there is a mobile equipment error message in the input string.
+ ///
+ /// The data received
+ /// true if there is a mobile equipment error message in the string, otherwiese false.
+ private bool IsMobileEquipmentError(string input)
+ {
+ return Regex.IsMatch(input, "\\r\\n\\+CME ERROR: (\\d+)\\r\\n");
+ }
+
+ ///
+ /// Checks if the communication to the device is open.
+ ///
+ /// true if the port is open, false otherwise.
+ /// The port is open after a auccessful call to and must be closed with
+ /// .
+ /// This function does not check if there is actually a device connected, use the
+ /// function for that.
+ ///
+ ///
+ ///
+ ///
+ public bool IsOpen()
+ {
+ bool flag;
+ bool isOpen;
+ lock (this)
+ {
+ if (this.port == null)
+ {
+ isOpen = false;
+ }
+ else
+ {
+ isOpen = this.port.IsOpen;
+ }
+ flag = isOpen;
+ }
+ return flag;
+ }
+
+ private bool IsSuccess(string input)
+ {
+ return input.IndexOf("\r\nOK\r\n") >= 0;
+ }
+
+ ///
+ /// AT+CMGL. Reads SMS messages from the current read/delete storage using the PDU mode.
+ ///
+ /// The message status
+ /// An array of objects representing the messages read.
+ /// Always switches to PDU mode at the beginning.
+ public ShortMessageFromPhone[] ListMessages(PhoneMessageStatus status)
+ {
+ ShortMessageFromPhone[] shortMessageFromPhoneArray;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.ActivatePduMode();
+ this.LogIt(LogLevel.Info, string.Concat("Reading messages, requesting status \"", status.ToString(), "\"..."));
+ string str = string.Concat("AT+CMGL=", (int)status);
+ string str1 = this.ExecAndReceiveMultiple(str);
+ ArrayList arrayLists = new ArrayList();
+ Regex regex = new Regex("\\+CMGL: (\\d+),(\\d+),(?:\"(\\w*)\")?,(\\d+)\\r\\n(\\w+)");
+ for (Match i = regex.Match(str1); i.Success; i = i.NextMatch())
+ {
+ int num = int.Parse(i.Groups[1].Value);
+ int num1 = int.Parse(i.Groups[2].Value);
+ string value = i.Groups[3].Value;
+ int num2 = int.Parse(i.Groups[4].Value);
+ string value1 = i.Groups[5].Value;
+ string[] strArrays = new string[8];
+ strArrays[0] = "index=";
+ strArrays[1] = num.ToString();
+ strArrays[2] = ", stat=";
+ strArrays[3] = num1.ToString();
+ strArrays[4] = ", alpha=\"";
+ strArrays[5] = value;
+ strArrays[6] = "\", length=";
+ strArrays[7] = num2.ToString();
+ this.LogIt(LogLevel.Info, string.Concat(strArrays));
+ ShortMessageFromPhone shortMessageFromPhone = new ShortMessageFromPhone(num, num1, value, num2, value1);
+ arrayLists.Add(shortMessageFromPhone);
+ }
+ int count = arrayLists.Count;
+ this.LogIt(LogLevel.Info, string.Concat(count.ToString(), " message(s) read."));
+ ShortMessageFromPhone[] shortMessageFromPhoneArray1 = new ShortMessageFromPhone[arrayLists.Count];
+ arrayLists.CopyTo(shortMessageFromPhoneArray1, 0);
+ shortMessageFromPhoneArray = shortMessageFromPhoneArray1;
+ }
+ return shortMessageFromPhoneArray;
+ }
+
+ ///
+ /// Lists the network operators detected by the phone.
+ ///
+ /// An array of objects containing the data of each operator.
+ /// If you want to determine the current operator, use the method.
+ public OperatorInfo2[] ListOperators()
+ {
+ OperatorInfo2[] operatorInfo2Array;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Listing operators...");
+ string str = this.ExecAndReceiveMultiple("AT+COPS=?");
+ ArrayList arrayLists = new ArrayList();
+ if (Regex.IsMatch(str, "\\+COPS: .*"))
+ {
+ Regex regex = new Regex("\\((\\d+),(?:\"([^\\(\\)\\,]+)\")?,(?:\"([^\\(\\)\\,]+)\")?,(?:\"(\\d+)\")?(?:,([^\\(\\)\\,]+))?\\)");
+ Match match = regex.Match(str);
+ while (match.Success)
+ {
+ int num = int.Parse(match.Groups[1].Value);
+ string value = match.Groups[2].Value;
+ string value1 = match.Groups[3].Value;
+ string str1 = match.Groups[4].Value;
+ string value2 = match.Groups[5].Value;
+ object[] objArray = new object[5];
+ objArray[0] = num;
+ objArray[1] = value;
+ objArray[2] = value1;
+ objArray[3] = str1;
+ objArray[4] = value2;
+ this.LogIt(LogLevel.Info, "stat={0}, longAlpha=\"{1}\", shortAlpha=\"{2}\", numeric=\"{3}\", act=\"{4}\"", objArray);
+ if (Enum.IsDefined(typeof(OperatorStatus), num))
+ {
+ OperatorStatus operatorStatu = (OperatorStatus)Enum.Parse(typeof(OperatorStatus), num.ToString());
+ OperatorInfo2 operatorInfo2 = new OperatorInfo2(operatorStatu, value, value1, str1, value2);
+ arrayLists.Add(operatorInfo2);
+ match = match.NextMatch();
+ }
+ else
+ {
+ throw new CommException(string.Concat("Unknown operator status ", num.ToString(), "."), str);
+ }
+ }
+ int count = arrayLists.Count;
+ this.LogIt(LogLevel.Info, string.Concat(count.ToString(), " operator(s) enumerated."));
+ OperatorInfo2[] operatorInfo2Array1 = new OperatorInfo2[arrayLists.Count];
+ arrayLists.CopyTo(operatorInfo2Array1, 0);
+ operatorInfo2Array = operatorInfo2Array1;
+ }
+ else
+ {
+ this.HandleCommError(str);
+ operatorInfo2Array = null;
+ }
+ }
+ return operatorInfo2Array;
+ }
+
+ private void LogIt(LogLevel level, string text)
+ {
+ if (this.LoglineAdded != null && this.logEnabled && level <= this.logLevel)
+ {
+ DateTime now = DateTime.Now;
+ string str = string.Format("{0} [gsmphone] {1}", now.ToString("HH:mm:ss.fff"), text);
+ LoglineAddedEventArgs loglineAddedEventArg = new LoglineAddedEventArgs(level, str);
+ lock (this.logQueue)
+ {
+ this.logQueue.Enqueue(loglineAddedEventArg);
+ }
+ }
+ }
+
+ private void LogIt(LogLevel level, string text, params object[] args)
+ {
+ if (this.LoglineAdded != null && this.logEnabled && level <= this.logLevel)
+ {
+ string str = string.Format(text, args);
+ DateTime now = DateTime.Now;
+ string str1 = string.Format("{0} [gsmphone] {1}", now.ToString("HH:mm:ss.fff"), str);
+ LoglineAddedEventArgs loglineAddedEventArg = new LoglineAddedEventArgs(level, str1);
+ lock (this.logQueue)
+ {
+ this.logQueue.Enqueue(loglineAddedEventArg);
+ }
+ }
+ }
+
+ private void LogItShow(LogLevel level, string data, string prefix, bool hideEmptyLines)
+ {
+ string[] strArrays = this.SplitLines(data);
+ if ((int)strArrays.Length != 0)
+ {
+ bool flag = false;
+ for (int i = 0; i < (int)strArrays.Length; i++)
+ {
+ if (!hideEmptyLines || hideEmptyLines && strArrays[i].Length > 0)
+ {
+ if (flag)
+ {
+ this.LogIt(level, strArrays[i].PadLeft(strArrays[i].Length + prefix.Length, ' '));
+ }
+ else
+ {
+ this.LogIt(level, string.Concat(prefix, strArrays[i]));
+ flag = true;
+ }
+ }
+ }
+ return;
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ private void LogItShow(LogLevel level, string data, string prefix)
+ {
+ this.LogItShow(level, data, prefix, false);
+ }
+
+ private void LogMemoryStatus(MemoryStatus status)
+ {
+ int used;
+ if (status.Total > 0)
+ {
+ used = (int)((double)status.Used / (double)status.Total * 100);
+ }
+ else
+ {
+ used = 0;
+ }
+ int num = used;
+ this.LogIt(LogLevel.Info, string.Format("Memory status: {0}/{1} ({2}% used)", status.Used, status.Total, num));
+ }
+
+ private void LogThread()
+ {
+ this.logQueue.Clear();
+ this.logThreadInitialized.Set();
+ while (!this.terminateLogThread.WaitOne(100, false))
+ {
+ while (this.DispatchLog())
+ {
+ }
+ }
+ while (this.DispatchLog())
+ {
+ }
+ this.logQueue.Clear();
+ }
+
+ private string MakeArrayString(string[] array)
+ {
+ StringBuilder stringBuilder = new StringBuilder();
+ string[] strArrays = array;
+ for (int i = 0; i < (int)strArrays.Length; i++)
+ {
+ string str = strArrays[i];
+ if (stringBuilder.Length > 0)
+ {
+ stringBuilder.Append(", ");
+ }
+ stringBuilder.Append(str);
+ }
+ return stringBuilder.ToString();
+ }
+
+ private string MakeQueueString(Queue queue)
+ {
+ StringBuilder stringBuilder = new StringBuilder();
+ lock (queue.SyncRoot)
+ {
+ foreach (string str in queue)
+ {
+ stringBuilder.Append(str);
+ }
+ }
+ return stringBuilder.ToString();
+ }
+
+ private PinStatus MapPinStatusStringToStatus(string s)
+ {
+ PinStatus pinStatu = PinStatus.Ready;
+ Dictionary strs = new Dictionary();
+ strs["READY"] = PinStatus.Ready;
+ strs["SIM PIN"] = PinStatus.SimPin;
+ strs["SIM PUK"] = PinStatus.SimPuk;
+ strs["PH-SIM PIN"] = PinStatus.PhoneToSimPin;
+ strs["PH-FSIM PIN"] = PinStatus.PhoneToFirstSimPin;
+ strs["PH-FSIM PUK"] = PinStatus.PhoneToFirstSimPuk;
+ strs["SIM PIN2"] = PinStatus.SimPin2;
+ strs["SIM PUK2"] = PinStatus.SimPuk2;
+ strs["PH-NET PIN"] = PinStatus.PhoneToNetworkPin;
+ strs["PH-NET PUK"] = PinStatus.PhoneToNetworkPuk;
+ strs["PH-NETSUB PIN"] = PinStatus.PhoneToNetworkSubsetPin;
+ strs["PH-NETSUB PUK"] = PinStatus.PhoneToNetworkSubsetPuk;
+ strs["PH-SP PIN"] = PinStatus.PhoneToServiceProviderPin;
+ strs["PH-SP PUK"] = PinStatus.PhoneToServiceProviderPuk;
+ strs["PH-CORP PIN"] = PinStatus.PhoneToCorporatePin;
+ strs["PH-CORP PUK"] = PinStatus.PhoneToCorporatePuk;
+ if (!strs.TryGetValue(s, out pinStatu))
+ {
+ throw new CommException(string.Concat("Unknown PIN status \"", s, "\"."));
+ }
+ else
+ {
+ return pinStatu;
+ }
+ }
+
+ private void OnMessageReceived(IMessageIndicationObject obj)
+ {
+ if (this.MessageReceived == null)
+ {
+ this.LogIt(LogLevel.Info, "No event handlers for MessageReceived event, message is ignored.");
+ return;
+ }
+ else
+ {
+ this.LogIt(LogLevel.Info, "Firing async MessageReceived event.");
+ MessageReceivedEventArgs messageReceivedEventArg = new MessageReceivedEventArgs(obj);
+ this.MessageReceived.BeginInvoke(this, messageReceivedEventArg, new AsyncCallback(this.AsyncCallback), null);
+ return;
+ }
+ }
+
+ private void OnPhoneConnected()
+ {
+ if (this.PhoneConnected != null)
+ {
+ this.LogIt(LogLevel.Info, "Firing async PhoneConnected event.");
+ this.PhoneConnected.BeginInvoke(this, EventArgs.Empty, new AsyncCallback(this.AsyncCallback), null);
+ }
+ }
+
+ private void OnPhoneDisconnected()
+ {
+ if (this.PhoneDisconnected != null)
+ {
+ this.LogIt(LogLevel.Info, "Firing async PhoneDisconnected event.");
+ this.PhoneDisconnected.BeginInvoke(this, EventArgs.Empty, new AsyncCallback(this.AsyncCallback), null);
+ }
+ }
+
+ private void OnReceiveComplete(int bytesReceived)
+ {
+ if (this.ReceiveComplete != null)
+ {
+ ProgressEventArgs progressEventArg = new ProgressEventArgs(bytesReceived);
+ this.ReceiveComplete.BeginInvoke(this, progressEventArg, new AsyncCallback(this.AsyncCallback), null);
+ }
+ }
+
+ private void OnReceiveProgress(int bytesReceived)
+ {
+ if (this.ReceiveProgress != null)
+ {
+ ProgressEventArgs progressEventArg = new ProgressEventArgs(bytesReceived);
+ this.ReceiveProgress.BeginInvoke(this, progressEventArg, new AsyncCallback(this.AsyncCallback), null);
+ }
+ }
+
+ ///
+ /// Opens the connection to the device.
+ ///
+ /// You can check the current connection state with the method.
+ ///
+ ///
+ ///
+ /// Connection to device already open.
+ /// Unable to open the port.
+ public void Open()
+ {
+ lock (this)
+ {
+ if (!this.IsOpen())
+ {
+ this.CreateLogThread();
+ try
+ {
+ this.OpenPort(this.portName, this.baudRate, this.timeout);
+ this.LogIt(LogLevel.Info, string.Concat("Port ", this.portName.ToString(), " now open."));
+ }
+ catch (Exception exception1)
+ {
+ Exception exception = exception1;
+ string str = string.Concat("Unable to open port ", this.portName, ": ", exception.Message);
+ this.LogIt(LogLevel.Error, str);
+ this.TerminateLogThread();
+ throw new CommException(str, exception);
+ }
+ this.CheckConnection();
+ try
+ {
+ this.CreateCommThread();
+ }
+ catch (Exception exception3)
+ {
+ Exception exception2 = exception3;
+ this.ClosePort();
+ this.TerminateLogThread();
+ throw new CommException("Unable to create communication thread.", exception2);
+ }
+ }
+ else
+ {
+ throw new InvalidOperationException("Port already open.");
+ }
+ }
+ }
+
+ private void OpenPort(string portName, int baudRate, int timeout)
+ {
+ this.LogIt(LogLevel.Info, "Initializing serial connection...");
+ this.LogIt(LogLevel.Info, string.Concat(" Port = ", portName));
+ this.LogIt(LogLevel.Info, string.Concat(" Baud rate = ", baudRate.ToString()));
+ this.LogIt(LogLevel.Info, string.Concat(" Timeout = ", timeout.ToString()));
+ if (this.port != null)
+ {
+ if (this.port.IsOpen)
+ {
+ throw new CommException("Port already open.");
+ }
+ }
+ else
+ {
+ SerialPortFixer.Execute(portName);
+ this.port = new SerialPort();
+ }
+ try
+ {
+ this.port.PortName = portName;
+ this.port.BaudRate = baudRate;
+ this.port.DataBits = 8;
+ this.port.StopBits = StopBits.One;
+ this.port.Parity = Parity.None;
+ this.port.ReadTimeout = timeout;
+ this.port.WriteTimeout = timeout;
+ this.port.Encoding = Encoding.GetEncoding(1252);
+ this.port.DataReceived += new SerialDataReceivedEventHandler(this.port_DataReceived);
+ this.port.Open();
+ this.port.DtrEnable = true;
+ this.port.RtsEnable = true;
+ }
+ catch (Exception exception)
+ {
+ if (this.port.IsOpen)
+ {
+ this.port.Close();
+ }
+ throw;
+ }
+ }
+
+ ///
+ /// Parses the memory status response of the CPMS command.
+ ///
+ /// A response to the +CPMS set command
+ /// A object containing the status information of the storages.
+ ///
+ /// Data for the ReceiveStorage (mem3) or for the WriteStorage (mem2) is null if there is no information available about it.
+ ///
+ private MessageMemoryStatus ParseMessageMemoryStatus(string input)
+ {
+ MessageMemoryStatus messageMemoryStatu;
+ Regex regex = new Regex("\\+CPMS: (\\d+),(\\d+)(?:,(\\d+),(\\d+))?(?:,(\\d+),(\\d+))?");
+ Match match = regex.Match(input);
+ if (!match.Success)
+ {
+ messageMemoryStatu = this.TryParseMessageMemoryStatus2(input);
+ if (messageMemoryStatu == null)
+ {
+ this.HandleCommError(input);
+ return null;
+ }
+ }
+ else
+ {
+ messageMemoryStatu = new MessageMemoryStatus();
+ int num = int.Parse(match.Groups[1].Value);
+ int num1 = int.Parse(match.Groups[2].Value);
+ messageMemoryStatu.ReadStorage = new MemoryStatus(num, num1);
+ if (match.Groups[3].Captures.Count > 0 && match.Groups[4].Captures.Count > 0)
+ {
+ int num2 = int.Parse(match.Groups[3].Value);
+ int num3 = int.Parse(match.Groups[4].Value);
+ messageMemoryStatu.WriteStorage = new MemoryStatus(num2, num3);
+ }
+ if (match.Groups[5].Captures.Count > 0 && match.Groups[6].Captures.Count > 0)
+ {
+ int num4 = int.Parse(match.Groups[5].Value);
+ int num5 = int.Parse(match.Groups[6].Value);
+ messageMemoryStatu.ReceiveStorage = new MemoryStatus(num4, num5);
+ }
+ }
+ return messageMemoryStatu;
+ }
+
+ ///
+ /// Parses the memory status response of the CPBS command.
+ ///
+ /// A response to the +CPBS set command
+ /// A object containing the memory details.
+ private MemoryStatusWithStorage ParsePhonebookMemoryStatus(string input)
+ {
+ Regex regex = new Regex("\\+CPBS: \"(\\w+)\",(\\d+),(\\d+)");
+ Match match = regex.Match(input);
+ if (!match.Success)
+ {
+ this.HandleCommError(input);
+ return null;
+ }
+ else
+ {
+ string value = match.Groups[1].Value;
+ int num = int.Parse(match.Groups[2].Value);
+ int num1 = int.Parse(match.Groups[3].Value);
+ MemoryStatusWithStorage memoryStatusWithStorage = new MemoryStatusWithStorage(value, num, num1);
+ return memoryStatusWithStorage;
+ }
+ }
+
+ private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
+ {
+ if (e.EventType == SerialData.Chars)
+ {
+ this.receiveNow.Set();
+ }
+ }
+
+ ///
+ /// AT+CMGR. Reads a single SMS message from the current read/delete storage using the PDU mode.
+ ///
+ /// The index of the message to read.
+ /// A object containing the message at the index specified.
+ /// Always switches to PDU mode at the beginning.
+ public ShortMessageFromPhone ReadMessage(int index)
+ {
+ ShortMessageFromPhone shortMessageFromPhone;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.ActivatePduMode();
+ this.LogIt(LogLevel.Info, string.Concat("Reading message from index ", index.ToString(), "..."));
+ string str = this.ExecAndReceiveMultiple(string.Concat("AT+CMGR=", index.ToString()));
+ Regex regex = new Regex("\\+CMGR: (\\d+),(?:\"(\\w*)\")?,(\\d+)\\r\\n(\\w+)");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.HandleCommError(str);
+ throw new CommException("Unexpected response.", str);
+ }
+ else
+ {
+ int num = int.Parse(match.Groups[1].Value);
+ string value = match.Groups[2].Value;
+ int num1 = int.Parse(match.Groups[3].Value);
+ string value1 = match.Groups[4].Value;
+ string[] strArrays = new string[6];
+ strArrays[0] = "stat=";
+ strArrays[1] = num.ToString();
+ strArrays[2] = ", alpha=\"";
+ strArrays[3] = value;
+ strArrays[4] = "\", length=";
+ strArrays[5] = num1.ToString();
+ this.LogIt(LogLevel.Info, string.Concat(strArrays));
+ ShortMessageFromPhone shortMessageFromPhone1 = new ShortMessageFromPhone(index, num, value, num1, value1);
+ shortMessageFromPhone = shortMessageFromPhone1;
+ }
+ }
+ return shortMessageFromPhone;
+ }
+
+ ///
+ /// Gets the entire phonebook of the currently selected phonebook storage.
+ ///
+ /// An array of objects.
+ public PhonebookEntry[] ReadPhonebookEntries()
+ {
+ int num = 0;
+ int num1 = 0;
+ int num2 = 0;
+ int num3 = 0;
+ PhonebookEntry[] phonebookEntryArray;
+ lock (this)
+ {
+ this.GetPhonebookSize(out num, out num1, out num2, out num3);
+ phonebookEntryArray = this.ReadPhonebookEntries(num, num1);
+ }
+ return phonebookEntryArray;
+ }
+
+ ///
+ /// AT+CPBR. Gets the specified range of phonebook entries.
+ ///
+ /// The first entry to get
+ /// The last entry to get
+ /// An array of objects
+ public PhonebookEntry[] ReadPhonebookEntries(int lowerBound, int upperBound)
+ {
+ PhonebookEntry[] phonebookEntryArray;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ object[] objArray = new object[5];
+ objArray[0] = "Getting phonebook from index ";
+ objArray[1] = lowerBound;
+ objArray[2] = " to ";
+ objArray[3] = upperBound;
+ objArray[4] = "...";
+ this.LogIt(LogLevel.Info, string.Concat(objArray));
+ string str = string.Concat("AT+CPBR=", lowerBound.ToString(), ",", upperBound.ToString());
+ string str1 = this.ExecAndReceiveMultiple(str);
+ phonebookEntryArray = this.DecodePhonebookStream(str1, "+CPBR: ");
+ }
+ return phonebookEntryArray;
+ }
+
+ ///
+ /// Receives raw data as a string.
+ ///
+ /// Receives the data received.
+ /// true if data was received, otherwise false.
+ private bool ReceiveInternal(out string input)
+ {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (string i = this.port.ReadExisting(); i.Length > 0; i = this.port.ReadExisting())
+ {
+ stringBuilder.Append(i);
+ }
+ input = stringBuilder.ToString();
+ return input.Length > 0;
+ }
+
+ ///
+ /// Disables access to the protocol level of the current connection.
+ ///
+ /// This method must be called as soon as the execution of the custom commands initiated
+ /// by is completed and allows for normal operations to continue.
+ ///
+ public void ReleaseProtocol()
+ {
+ Monitor.Exit(this);
+ }
+
+ ///
+ /// AT+CGMI. Requests manufacturer identification.
+ ///
+ /// The product manufacturer identification.
+ public string RequestManufacturer()
+ {
+ string str;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Requesting manufacturer...");
+ string str1 = this.ExecAndReceiveMultiple("AT+CGMI");
+ string str2 = this.TrimLineBreaks(str1);
+ this.LogIt(LogLevel.Info, string.Concat("Manufacturer = \"", str2, "\""));
+ str = str2;
+ }
+ return str;
+ }
+
+ ///
+ /// AT+CGMM. Requests model identification.
+ ///
+ /// The product model identification.
+ public string RequestModel()
+ {
+ string str;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Requesting model...");
+ string str1 = this.ExecAndReceiveMultiple("AT+CGMM");
+ string str2 = this.TrimLineBreaks(str1);
+ this.LogIt(LogLevel.Info, string.Concat("Model = \"", str2, "\""));
+ str = str2;
+ }
+ return str;
+ }
+
+ ///
+ /// AT+CGMR. Requests revision identification.
+ ///
+ /// The product revision identification.
+ public string RequestRevision()
+ {
+ string str;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Requesting revision...");
+ string str1 = this.ExecAndReceiveMultiple("AT+CGMR");
+ string str2 = this.TrimLineBreaks(str1);
+ this.LogIt(LogLevel.Info, string.Concat("Revision = \"", str2, "\""));
+ str = str2;
+ }
+ return str;
+ }
+
+ ///
+ /// AT+CGSN. Requests serial number identification.
+ ///
+ /// The product serial number.
+ public string RequestSerialNumber()
+ {
+ string str;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Requesting serial number...");
+ string str1 = this.ExecAndReceiveMultiple("AT+CGSN");
+ string str2 = this.TrimLineBreaks(str1);
+ this.LogIt(LogLevel.Info, string.Concat("Serial Number = \"", str2, "\""));
+ str = str2;
+ }
+ return str;
+ }
+
+ ///
+ /// ATZ. Settings that are not stored in a profile will be reset to their factory defaults.
+ ///
+ public void ResetToDefaultConfig()
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Resetting to default configuration...");
+ this.ExecAndReceiveMultiple("ATZ");
+ }
+ }
+
+ ///
+ /// AT+CSCS. Selects the character set.
+ ///
+ /// The character set to use.
+ /// This command informs the data card of which character set is used by the TE. The data card is
+ /// then able to convert character strings correctly between TE and ME character sets. When the data card-TE
+ /// interface is set to 8-bit operation and the TE uses a 7-bit alphabet, the highest bit shall be set to
+ /// zero. This setting affects text mode SMS data and alpha fields in the phone book memory. If the ME is
+ /// using the GSM default alphabet, its characters shall be padded with the 8th bit (zero) before
+ /// converting them to hexadecimal numbers (that is, a 7-bit alphabet is not packed in the SMS-style
+ /// packing).
+ ///
+ ///
+ ///
+ public void SelectCharacterSet(string charset)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, string.Concat("Selecting character set \"", charset, "\"..."));
+ this.ExecAndReceiveMultiple(string.Concat("AT+CSCS=\"", charset, "\""));
+ }
+ }
+
+ ///
+ /// AT+CSMS. Selects the specified messaging service.
+ ///
+ /// The service to select. Specifies the compatibility level of the SMS AT commands.
+ /// The requirement of service setting 1 depends on specific commands.
+ ///
+ /// ME supports mobile terminated messages
+ /// ME supports mobile originated messages
+ /// ME supports broadcast type messages
+ public void SelectMessageService(int service, out int mt, out int mo, out int bm)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ string str = this.ExecAndReceiveMultiple(string.Concat("AT+CSMS=", service.ToString()));
+ Regex regex = new Regex("\\+CSMS: (\\d+),(\\d+),(\\d+)");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.HandleCommError(str);
+ throw new CommException("Unexpected response.", str);
+ }
+ else
+ {
+ mt = int.Parse(match.Groups[1].Value);
+ mo = int.Parse(match.Groups[2].Value);
+ bm = int.Parse(match.Groups[3].Value);
+ }
+ }
+ }
+
+ ///
+ /// AT+CPBS. Selects the storage to use for phonebook operations.
+ ///
+ /// The storage to use.
+ /// The memory status of the selected storage.
+ public void SelectPhonebookStorage(string storage)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, string.Concat("Selecting \"", storage, "\" phonebook memory..."));
+ this.ExecAndReceiveMultiple(string.Concat("AT+CPBS=\"", storage, "\""));
+ }
+ }
+
+ ///
+ /// AT+CPMS. Selects the storage to use for read and delete operations.
+ ///
+ /// The storage to use
+ /// The memory status of the selected storage.
+ /// This selects the preferred message storage "mem1" on the device.
+ public MemoryStatus SelectReadStorage(string storage)
+ {
+ MemoryStatus memoryStatu;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, string.Concat("Selecting \"", storage, "\" as read storage..."));
+ string str = this.ExecAndReceiveMultiple(string.Concat("AT+CPMS=\"", storage, "\""));
+ MessageMemoryStatus messageMemoryStatu = this.ParseMessageMemoryStatus(str);
+ MemoryStatus readStorage = messageMemoryStatu.ReadStorage;
+ this.LogMemoryStatus(readStorage);
+ memoryStatu = readStorage;
+ }
+ return memoryStatu;
+ }
+
+ ///
+ /// AT+CPMS. Selects the storage to use for write and send operations.
+ ///
+ /// The storage to use
+ /// The memory status of the selected storage
+ /// This selects the preferred message storage "mem2" on the device. Additionaly, the "mem1" storage
+ /// is also set to the same storage since the read storage must also be set when selecting the
+ /// write storage.
+ public MemoryStatus SelectWriteStorage(string storage)
+ {
+ MemoryStatus memoryStatu;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, string.Concat("Selecting \"", storage, "\" as write storage..."));
+ string str = storage;
+ string str1 = storage;
+ string[] strArrays = new string[5];
+ strArrays[0] = "AT+CPMS=\"";
+ strArrays[1] = str;
+ strArrays[2] = "\",\"";
+ strArrays[3] = str1;
+ strArrays[4] = "\"";
+ string str2 = string.Concat(strArrays);
+ string str3 = this.ExecAndReceiveMultiple(str2);
+ MessageMemoryStatus messageMemoryStatu = this.ParseMessageMemoryStatus(str3);
+ MemoryStatus writeStorage = messageMemoryStatu.WriteStorage;
+ this.LogMemoryStatus(writeStorage);
+ memoryStatu = writeStorage;
+ }
+ return memoryStatu;
+ }
+
+ ///
+ /// Sends raw data as a string.
+ ///
+ /// The data to send.
+ /// Specifies if the data sent should be logged.
+ /// Send and receive buffers are cleared before sending.
+ private void SendInternal(string output, bool logIt)
+ {
+ if (logIt)
+ {
+ this.LogItShow(LogLevel.Verbose, output, "<< ");
+ }
+ this.port.DiscardOutBuffer();
+ this.port.DiscardInBuffer();
+ this.port.Write(output);
+ }
+
+ ///
+ /// AT+CMGS. Sends an SMS message using PDU mode.
+ ///
+ /// The PDU stream to send
+ /// The actual length of the PDU (not counting the SMSC data)
+ /// The message reference
+ /// Always switches to PDU mode at the beginning.
+ public byte SendMessage(string pdu, int actualLength)
+ {
+ byte num;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.ActivatePduMode();
+ this.LogIt(LogLevel.Info, "Sending message...");
+ this.ExecAndReceiveAnything(string.Concat("AT+CMGS=", actualLength.ToString()), "\\r\\n> ");
+ this.Send(string.Concat(pdu, (char)26));
+ string str = this.ReceiveMultiple();
+ byte num1 = 0;
+ Regex regex = new Regex("\\+CMGS: (\\d+)(,(\\w+))*");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.LogIt(LogLevel.Warning, string.Concat("Could not get message reference. Answer received was: \"", str, "\""));
+ }
+ else
+ {
+ num1 = (byte)int.Parse(match.Groups[1].Value);
+ this.LogIt(LogLevel.Info, string.Concat("Message reference = ", num1.ToString()));
+ }
+ num = num1;
+ }
+ return num;
+ }
+
+ ///
+ /// AT+CNMI. Selects the procedure for indicating new messages received from the network.
+ ///
+ /// A structure containing the
+ /// detailed settings.
+ /// The function switches to the PDU mode before setting the notifications. This
+ /// causes all short messages, that are directly routed, to be presented in PDU mode. If the mode
+ /// is changed (such as a switch to the text mode), all indications (containing a message) following the
+ /// change are sent in the new mode.
+ ///
+ public void SetMessageIndications(MessageIndicationSettings settings)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.ActivatePduMode();
+ this.LogIt(LogLevel.Info, "Setting message notifications...");
+ object[] mode = new object[5];
+ mode[0] = settings.Mode;
+ mode[1] = settings.DeliverStyle;
+ mode[2] = settings.CellBroadcastStyle;
+ mode[3] = settings.StatusReportStyle;
+ mode[4] = settings.BufferSetting;
+ string str = string.Format("AT+CNMI={0},{1},{2},{3},{4}", mode);
+ this.ExecAndReceiveMultiple(str);
+ }
+ }
+
+ ///
+ /// AT+CMMS. Sets the SMS batch mode.
+ ///
+ /// The new mode to set.
+ public void SetMoreMessagesToSend(MoreMessagesMode mode)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ object[] objArray = new object[1];
+ objArray[0] = mode;
+ this.LogIt(LogLevel.Info, "Setting more messages mode {0}...", objArray);
+ string str = string.Format("AT+CMMS={0}", (int)mode);
+ this.ExecAndReceiveMultiple(str);
+ }
+ }
+
+ private void SetNewConnectionState(bool newState)
+ {
+ if (newState != this.connectionState)
+ {
+ this.connectionState = newState;
+ if (!this.connectionState)
+ {
+ this.LogIt(LogLevel.Info, "Phone disconnected.");
+ this.OnPhoneDisconnected();
+ }
+ else
+ {
+ this.LogIt(LogLevel.Info, "Phone connected.");
+ this.OnPhoneConnected();
+ return;
+ }
+ }
+ }
+
+ ///
+ /// AT+CSCA. Sets the SMS Service Center Address.
+ ///
+ /// An object containing the new address
+ /// This command changes the SMSC address, through which SMS messages are transmitted.
+ /// In text mode, this setting is used by SMS sending and SMS writing commands. In PDU mode, this setting is
+ /// used by the same commands, but only when the length of the SMSC address coded into the PDU data equals
+ /// zero.
+ public void SetSmscAddress(AddressData data)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ object[] address = new object[2];
+ address[0] = data.Address;
+ int typeOfAddress = data.TypeOfAddress;
+ address[1] = typeOfAddress.ToString();
+ this.LogIt(LogLevel.Info, "Setting SMSC address to \"{0}\", type {1}...", address);
+ int num = data.TypeOfAddress;
+ string str = string.Format("AT+CSCA=\"{0}\",{1}", data.Address, num.ToString());
+ this.ExecAndReceiveMultiple(str);
+ }
+ }
+
+ ///
+ /// AT+CSCA. Sets the SMS Service Center Address.
+ ///
+ /// The new SMSC address
+ /// This command changes the SMSC address, through which SMS messages are transmitted.
+ /// In text mode, setting is used by send and write commands. In PDU mode, setting is used by the same
+ /// commands, but only when the length of the SMSC address coded into the PDU data equals zero.
+ public void SetSmscAddress(string address)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ object[] objArray = new object[1];
+ objArray[0] = address;
+ this.LogIt(LogLevel.Info, "Setting SMSC address to \"{0}\"...", objArray);
+ string str = string.Format("AT+CSCA=\"{0}\"", address);
+ this.ExecAndReceiveMultiple(str);
+ }
+ }
+
+ private string[] SplitLines(string data)
+ {
+ char chr = '\r';
+ char chr1 = '\n';
+ char chr2 = '\r';
+ data = data.Replace(string.Concat(chr.ToString(), chr1.ToString()), chr2.ToString());
+ char[] chrArray = new char[1];
+ chrArray[0] = '\r';
+ return data.Split(chrArray);
+ }
+
+ private void TerminateCommThread()
+ {
+ if (this.IsCommThreadRunning())
+ {
+ this.terminateCommThread.Set();
+ try
+ {
+ if (!this.commThread.Join(10000))
+ {
+ this.LogIt(LogLevel.Warning, "Communication thread did not exit within the timeout, aborting thread.");
+ this.commThread.Abort();
+ }
+ }
+ catch (Exception exception1)
+ {
+ Exception exception = exception1;
+ this.LogIt(LogLevel.Error, string.Concat("Error while terminating comm thread: ", exception.Message));
+ }
+ this.commThread = null;
+ }
+ }
+
+ private void TerminateLogThread()
+ {
+ if (this.logThread != null && this.logThread.IsAlive)
+ {
+ this.LogIt(LogLevel.Info, "Log thread is terminating.");
+ this.terminateLogThread.Set();
+ try
+ {
+ if (!this.logThread.Join(10000))
+ {
+ this.logThread.Abort();
+ }
+ }
+ catch (Exception exception)
+ {
+ }
+ this.logThread = null;
+ }
+ }
+
+ ///
+ /// Removes all leading and trailing line termination characters from a string.
+ ///
+ /// The string to trim.
+ /// The modified string.
+ private string TrimLineBreaks(string input)
+ {
+ char[] chrArray = new char[2];
+ chrArray[0] = '\r';
+ chrArray[1] = '\n';
+ return input.Trim(chrArray);
+ }
+
+ ///
+ /// Tries to parse an alternative memory status response of the CPMS command.
+ ///
+ /// A response to the +CPMS set command
+ /// A object containing the status information of the storages
+ /// if successful, otherwise null.
+ private MessageMemoryStatus TryParseMessageMemoryStatus2(string input)
+ {
+ MessageMemoryStatus messageMemoryStatu = null;
+ Regex regex = new Regex("\\+CPMS: \"(\\w+)\",(\\d+),(\\d+),\"(\\w+)\",(\\d+),(\\d+)(?:,\"(\\w+)\",(\\d+),(\\d+))?");
+ Match match = regex.Match(input);
+ if (match.Success)
+ {
+ messageMemoryStatu = new MessageMemoryStatus();
+ string value = match.Groups[1].Value;
+ int num = int.Parse(match.Groups[2].Value);
+ int num1 = int.Parse(match.Groups[3].Value);
+ string str = match.Groups[4].Value;
+ int num2 = int.Parse(match.Groups[5].Value);
+ int num3 = int.Parse(match.Groups[6].Value);
+ messageMemoryStatu.ReadStorage = new MemoryStatusWithStorage(value, num, num1);
+ messageMemoryStatu.WriteStorage = new MemoryStatusWithStorage(str, num2, num3);
+ if (match.Groups[7].Captures.Count > 0)
+ {
+ string value1 = match.Groups[7].Value;
+ int num4 = int.Parse(match.Groups[8].Value);
+ int num5 = int.Parse(match.Groups[9].Value);
+ messageMemoryStatu.ReceiveStorage = new MemoryStatusWithStorage(value1, num4, num5);
+ }
+ }
+ return messageMemoryStatu;
+ }
+
+ private void VerifyValidConnection()
+ {
+ if (this.IsOpen())
+ {
+ if (this.connectionState)
+ {
+ return;
+ }
+ else
+ {
+ this.LogIt(LogLevel.Error, "No phone connected.");
+ throw new CommException("No phone connected.");
+ }
+ }
+ else
+ {
+ this.LogIt(LogLevel.Error, "Port not open.");
+ throw new InvalidOperationException("Port not open.");
+ }
+ }
+
+ ///
+ /// AT+CMGW. Stores an SMS message in the current write/send storage using PDU mode.
+ ///
+ /// The message in PDU format
+ /// The actual length of the PDU (not counting the SMSC data)
+ /// The status that the message should get when saved.
+ /// The index of the message. If the index could not be retrieved, zero is returned.
+ /// The message is saved with a status predefined by the phone
+ /// This function always switches to the PDU mode at the beginning.
+ public int WriteMessageToMemory(string pdu, int actualLength, int status)
+ {
+ int memoryPart2;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.ActivatePduMode();
+ this.LogIt(LogLevel.Info, "Writing message to memory...");
+ this.ExecAndReceiveAnything(string.Concat("AT+CMGW=", actualLength.ToString(), ",", status.ToString()), "\\r\\n> ");
+ memoryPart2 = this.WriteMessageToMemoryPart2(pdu);
+ }
+ return memoryPart2;
+ }
+
+ ///
+ /// AT+CMGW. Stores an SMS message in the current write/send storage using PDU mode.
+ ///
+ /// The message in PDU format
+ /// The actual length of the PDU (not counting the SMSC data)
+ /// The index of the message. If the index could not be retrieved, zero is returned.
+ /// The message is saved with a status predefined by the phone
+ /// This function always switches to the PDU mode at the beginning.
+ public int WriteMessageToMemory(string pdu, int actualLength)
+ {
+ int memoryPart2;
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.ActivatePduMode();
+ this.LogIt(LogLevel.Info, "Writing message to memory...");
+ this.ExecAndReceiveAnything(string.Concat("AT+CMGW=", actualLength.ToString()), "\\r\\n> ");
+ memoryPart2 = this.WriteMessageToMemoryPart2(pdu);
+ }
+ return memoryPart2;
+ }
+
+ private int WriteMessageToMemoryPart2(string pdu)
+ {
+ this.Send(string.Concat(pdu, (char)26));
+ string str = this.ReceiveMultiple();
+ int num = 0;
+ Regex regex = new Regex("\\+CMGW: (\\d+)");
+ Match match = regex.Match(str);
+ if (!match.Success)
+ {
+ this.LogIt(LogLevel.Warning, string.Concat("Could not get message index. Answer received was: \"", str, "\""));
+ }
+ else
+ {
+ num = int.Parse(match.Groups[1].Value);
+ this.LogIt(LogLevel.Info, string.Concat("Message index = ", num.ToString()));
+ }
+ return num;
+ }
+
+ ///
+ /// AT+CPBW. Creates a new phonebook entry.
+ ///
+ /// The entry to write.
+ /// The property of the entry is ignored,
+ /// the entry is always saved in the first free location. All other properties must be set
+ /// correctly.
+ public void WritePhonebookEntry(PhonebookEntry entry)
+ {
+ lock (this)
+ {
+ this.VerifyValidConnection();
+ this.LogIt(LogLevel.Info, "Writing phonebook entry...");
+ object[] number = new object[7];
+ number[0] = "AT+CPBW=,\"";
+ number[1] = entry.Number;
+ number[2] = "\",";
+ number[3] = entry.Type;
+ number[4] = ",\"";
+ number[5] = entry.Text;
+ number[6] = "\"";
+ string str = string.Concat(number);
+ this.ExecAndReceiveMultiple(str);
+ }
+ }
+
+ ///
+ /// The event that occurs when a new line was added to the log.
+ ///
+ public event LoglineAddedEventHandler LoglineAdded;
+
+ ///
+ /// The event that occurs when a new SMS message was received.
+ ///
+ public event MessageReceivedEventHandler MessageReceived;
+
+ /// The event that occurs when the phone is connected.
+ public event EventHandler PhoneConnected;
+
+ /// The event that occurs when the phone is disconnected.
+ public event EventHandler PhoneDisconnected;
+
+ /// The event that occurs when receiving from the phone is completed.
+ /// This event is only fired by reading operations that may take longer to complete.
+ public event ProgressEventHandler ReceiveComplete;
+
+ /// The event that occurs when new data was received from the phone.
+ /// This event is only fired by reading operations that may take longer to complete.
+ public event ProgressEventHandler ReceiveProgress;
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/IMessageIndicationObject.cs b/GSMCommunication/GsmCommunication/IMessageIndicationObject.cs
new file mode 100644
index 0000000..836ed48
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/IMessageIndicationObject.cs
@@ -0,0 +1,10 @@
+///
+/// The interface identifying an object as being used for indicating new incoming messages.
+///
+namespace GsmComm.GsmCommunication
+{
+ public interface IMessageIndicationObject
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/IProtocol.cs b/GSMCommunication/GsmCommunication/IProtocol.cs
new file mode 100644
index 0000000..ea9da43
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/IProtocol.cs
@@ -0,0 +1,91 @@
+using System;
+
+///
+/// Provides an interface for low-level access to the device.
+///
+namespace GsmComm.GsmCommunication
+{
+ public interface IProtocol
+ {
+ ///
+ /// Executes the specified command and reads multiple times from the phone
+ /// until a specific pattern is detected in the response.
+ ///
+ /// The command to execute.
+ /// The regular expression pattern that the received data must match to stop
+ /// reading.
+ /// The response received.
+ ///
+ ///
+ ///
+ string ExecAndReceiveAnything(string command, string pattern);
+
+ /// Executes the specified command and reads multiple times from the phone
+ /// until one of the defined message termination patterns is detected in the response.
+ /// The command to execute.
+ /// The response received.
+ ///
+ ///
+ ///
+ string ExecAndReceiveMultiple(string command);
+
+ /// Executes the specified command and reads a single response.
+ /// The command to execute.
+ /// The response received.
+ ///
+ /// This method returns whatever response comes in from the phone during a single read operation.
+ /// The response received may not be complete.
+ /// If you want to ensure that always complete responses are read, use instead.
+ ///
+ ///
+ ///
+ ///
+ ///
+ string ExecCommand(string command);
+
+ ///
+ /// Executes the specified command and reads a single response.
+ /// The command to execute.
+ /// The message text for the exception if no data is received.
+ /// The response received.
+ ///
+ /// This method returns whatever response comes in from the phone during a single read operation.
+ /// The response received may not be complete.
+ /// If you want to ensure that always complete responses are read, use instead.
+ ///
+ ///
+ ///
+ ///
+ ///
+ string ExecCommand(string command, string receiveErrorMessage);
+
+ ///
+ /// Receives raw string data.
+ /// The data received.
+ /// true if reception was successful, otherwise false.
+ ///
+ bool Receive(out string input);
+
+ /// Reads multiple times from the phone until a specific pattern is detected in the response.
+ /// The response received.
+ /// The regular expression pattern that the received data must match to
+ /// stop reading. Can be an empty string if the pattern should not be checked.
+ ///
+ ///
+ ///
+ string ReceiveAnything(string pattern);
+
+ /// Reads multiple times from the phone until one of the defined
+ /// message termination patterns is detected in the response.
+ /// The response received.
+ ///
+ ///
+ ///
+ string ReceiveMultiple();
+
+ /// Sends raw string data.
+ /// The data to send.
+ ///
+ void Send(string output);
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/IdentificationInfo.cs b/GSMCommunication/GsmCommunication/IdentificationInfo.cs
new file mode 100644
index 0000000..84d6369
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/IdentificationInfo.cs
@@ -0,0 +1,79 @@
+using System;
+
+///
+/// Contains information that identify a mobile phone.
+///
+namespace GsmComm.GsmCommunication
+{
+ public struct IdentificationInfo
+ {
+ private string manufacturer;
+
+ private string model;
+
+ private string revision;
+
+ private string serialNumber;
+
+ ///
+ /// Gets or sets the manufacturer.
+ ///
+ public string Manufacturer
+ {
+ get
+ {
+ return this.manufacturer;
+ }
+ set
+ {
+ this.manufacturer = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the model.
+ ///
+ public string Model
+ {
+ get
+ {
+ return this.model;
+ }
+ set
+ {
+ this.model = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the revision.
+ ///
+ public string Revision
+ {
+ get
+ {
+ return this.revision;
+ }
+ set
+ {
+ this.revision = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the serial number.
+ ///
+ public string SerialNumber
+ {
+ get
+ {
+ return this.serialNumber;
+ }
+ set
+ {
+ this.serialNumber = value;
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/IndicationBufferSetting.cs b/GSMCommunication/GsmCommunication/IndicationBufferSetting.cs
new file mode 100644
index 0000000..83f3621
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/IndicationBufferSetting.cs
@@ -0,0 +1,19 @@
+///
+/// Specifies what should happen to the TA's indication buffer.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum IndicationBufferSetting
+ {
+ ///
+ /// The TA buffer of unsolicited result codes is flushed to the TE when an
+ /// other than is entered.
+ ///
+ Flush,
+ ///
+ /// TA buffer of unsolicited result codes defined within this command is cleared when an
+ /// other than is entered.
+ ///
+ Clear
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/LogLevel.cs b/GSMCommunication/GsmCommunication/LogLevel.cs
new file mode 100644
index 0000000..b38e28b
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/LogLevel.cs
@@ -0,0 +1,25 @@
+///
+/// Specifies the level of an entry written to the log.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum LogLevel
+ {
+ ///
+ /// Error
+ ///
+ Error,
+ ///
+ /// Warning
+ ///
+ Warning,
+ ///
+ /// Information
+ ///
+ Info,
+ ///
+ /// Additional information
+ ///
+ Verbose
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/LoglineAddedEventArgs.cs b/GSMCommunication/GsmCommunication/LoglineAddedEventArgs.cs
new file mode 100644
index 0000000..3520c08
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/LoglineAddedEventArgs.cs
@@ -0,0 +1,62 @@
+using System;
+
+///
+/// Provides data for the event.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class LoglineAddedEventArgs
+ {
+ private LogLevel level;
+
+ private string text;
+
+ ///
+ /// Gets the log level.
+ ///
+ public LogLevel Level
+ {
+ get
+ {
+ return this.level;
+ }
+ }
+
+ ///
+ /// Gets the log text.
+ ///
+ public string Text
+ {
+ get
+ {
+ return this.text;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The log level.
+ /// The log text.
+ public LoglineAddedEventArgs(LogLevel level, string text)
+ {
+ if (Enum.IsDefined(typeof(LogLevel), level))
+ {
+ if (text != null)
+ {
+ this.level = level;
+ this.text = text;
+ return;
+ }
+ else
+ {
+ throw new ArgumentNullException("text");
+ }
+ }
+ else
+ {
+ throw new ArgumentException(string.Concat("Invalid log level \"", level, "\"."));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/LoglineAddedEventHandler.cs b/GSMCommunication/GsmCommunication/LoglineAddedEventHandler.cs
new file mode 100644
index 0000000..960bc9d
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/LoglineAddedEventHandler.cs
@@ -0,0 +1,11 @@
+using System;
+
+///
+/// The method that handles the event.
+///
+/// The origin of the event.
+/// The data for the event.
+namespace GsmComm.GsmCommunication
+{
+ public delegate void LoglineAddedEventHandler(object sender, LoglineAddedEventArgs e);
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MemoryLocation.cs b/GSMCommunication/GsmCommunication/MemoryLocation.cs
new file mode 100644
index 0000000..32b6a97
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MemoryLocation.cs
@@ -0,0 +1,47 @@
+using System;
+
+///
+/// Contains the memory location of a saved message.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class MemoryLocation : IMessageIndicationObject
+ {
+ private string storage;
+
+ private int index;
+
+ ///
+ /// Gets the message index within the specified .
+ ///
+ public int Index
+ {
+ get
+ {
+ return this.index;
+ }
+ }
+
+ ///
+ /// Gets the storage where the message is saved.
+ ///
+ public string Storage
+ {
+ get
+ {
+ return this.storage;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The storage where the message is saved.
+ /// The message index within the specified storage.
+ public MemoryLocation(string storage, int index)
+ {
+ this.storage = storage;
+ this.index = index;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MemoryStatus.cs b/GSMCommunication/GsmCommunication/MemoryStatus.cs
new file mode 100644
index 0000000..8e99aef
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MemoryStatus.cs
@@ -0,0 +1,47 @@
+using System;
+
+///
+/// Contains the memory status of a specific storage.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class MemoryStatus
+ {
+ private int used;
+
+ private int total;
+
+ ///
+ /// Gets the total capacity of the storage.
+ ///
+ public int Total
+ {
+ get
+ {
+ return this.total;
+ }
+ }
+
+ ///
+ /// Gets the number of messages in the storage.
+ ///
+ public int Used
+ {
+ get
+ {
+ return this.used;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The number of messages in the storage
+ /// The total capacity of the storage
+ public MemoryStatus(int used, int total)
+ {
+ this.used = used;
+ this.total = total;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MemoryStatusWithStorage.cs b/GSMCommunication/GsmCommunication/MemoryStatusWithStorage.cs
new file mode 100644
index 0000000..b14e0ad
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MemoryStatusWithStorage.cs
@@ -0,0 +1,34 @@
+using System;
+
+///
+/// Contains the memory status of a specific storage, including the storage type.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class MemoryStatusWithStorage : MemoryStatus
+ {
+ private string storage;
+
+ ///
+ /// Gets the storage that this memory status applies to.
+ ///
+ public string Storage
+ {
+ get
+ {
+ return this.storage;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The storage that this memory status applies to
+ /// The number of messages in the storage
+ /// The total capacity of the storage
+ public MemoryStatusWithStorage(string storage, int used, int total) : base(used, total)
+ {
+ this.storage = storage;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MessageErrorEventArgs.cs b/GSMCommunication/GsmCommunication/MessageErrorEventArgs.cs
new file mode 100644
index 0000000..1b96df5
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MessageErrorEventArgs.cs
@@ -0,0 +1,34 @@
+using GsmComm.PduConverter;
+using System;
+
+///
+/// Provides data for the error events that deal with message sending.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class MessageErrorEventArgs : MessageEventArgs
+ {
+ private Exception exception;
+
+ ///
+ /// Gets the exception that caused the error.
+ ///
+ public Exception Exception
+ {
+ get
+ {
+ return this.exception;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The message that failed sending.
+ /// The exception that caused the error.
+ public MessageErrorEventArgs(OutgoingSmsPdu pdu, Exception exception) : base(pdu)
+ {
+ this.exception = exception;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MessageEventArgs.cs b/GSMCommunication/GsmCommunication/MessageEventArgs.cs
new file mode 100644
index 0000000..1ef02d5
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MessageEventArgs.cs
@@ -0,0 +1,33 @@
+using GsmComm.PduConverter;
+using System;
+
+///
+/// Provides data for the events that deal with message sending.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class MessageEventArgs : EventArgs
+ {
+ private OutgoingSmsPdu pdu;
+
+ ///
+ /// The message that was dealt with.
+ ///
+ public OutgoingSmsPdu Pdu
+ {
+ get
+ {
+ return this.pdu;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The message that was dealt with.
+ public MessageEventArgs(OutgoingSmsPdu pdu)
+ {
+ this.pdu = pdu;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MessageIndicationHandlers.cs b/GSMCommunication/GsmCommunication/MessageIndicationHandlers.cs
new file mode 100644
index 0000000..9c6a1c4
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MessageIndicationHandlers.cs
@@ -0,0 +1,349 @@
+using GsmComm.PduConverter;
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+///
+/// This class contains the handlers for unsolicited messages sent by the phone. It is for use by the GsmPhone
+/// class only and must not be made public.
+///
+namespace GsmComm.GsmCommunication
+{
+ internal class MessageIndicationHandlers
+ {
+ private const string deliverMemoryIndication = "\\+CMTI: \"(\\w+)\",(\\d+)";
+
+ private const string deliverMemoryIndicationStart = "\\+CMTI: ";
+
+ private const string deliverPduModeIndication = "\\+CMT: (\\w*),(\\d+)\\r\\n(\\w+)";
+
+ private const string deliverPduModeIndicationStart = "\\+CMT: ";
+
+ private const string statusReportMemoryIndication = "\\+CDSI: \"(\\w+)\",(\\d+)";
+
+ private const string statusReportMemoryIndicationStart = "\\+CDSI: ";
+
+ private const string statusReportPduModeIndication = "\\+CDS: (\\d+)\\r\\n(\\w+)";
+
+ private const string statusReportPduModeIndicationStart = "\\+CDS: ";
+
+ private List messages;
+
+ public MessageIndicationHandlers()
+ {
+ this.messages = new List();
+ MessageIndicationHandlers.UnsoMessage unsoMessage = new MessageIndicationHandlers.UnsoMessage("\\+CMTI: \"(\\w+)\",(\\d+)", new MessageIndicationHandlers.UnsoHandler(this.HandleDeliverMemoryIndication));
+ unsoMessage.StartPattern = "\\+CMTI: ";
+ unsoMessage.Description = "New SMS-DELIVER received (indicated by memory location)";
+ this.messages.Add(unsoMessage);
+ MessageIndicationHandlers.UnsoMessage unsoCompleteChecker = new MessageIndicationHandlers.UnsoMessage("\\+CMT: (\\w*),(\\d+)\\r\\n(\\w+)", new MessageIndicationHandlers.UnsoHandler(this.HandleDeliverPduModeIndication));
+ unsoCompleteChecker.StartPattern = "\\+CMT: ";
+ unsoCompleteChecker.Description = "New SMS-DELIVER received (indicated by PDU mode version)";
+ unsoCompleteChecker.CompleteChecker = new MessageIndicationHandlers.UnsoCompleteChecker(this.IsCompleteDeliverPduModeIndication);
+ this.messages.Add(unsoCompleteChecker);
+ MessageIndicationHandlers.UnsoMessage unsoMessage1 = new MessageIndicationHandlers.UnsoMessage("\\+CDSI: \"(\\w+)\",(\\d+)", new MessageIndicationHandlers.UnsoHandler(this.HandleStatusReportMemoryIndication));
+ unsoMessage1.StartPattern = "\\+CDSI: ";
+ unsoMessage1.Description = "New SMS-STATUS-REPORT received (indicated by memory location)";
+ this.messages.Add(unsoMessage1);
+ MessageIndicationHandlers.UnsoMessage unsoCompleteChecker1 = new MessageIndicationHandlers.UnsoMessage("\\+CDS: (\\d+)\\r\\n(\\w+)", new MessageIndicationHandlers.UnsoHandler(this.HandleStatusReportPduModeIndication));
+ unsoCompleteChecker1.StartPattern = "\\+CDS: ";
+ unsoCompleteChecker1.Description = "New SMS-STATUS-REPORT received (indicated by PDU mode version)";
+ unsoCompleteChecker1.CompleteChecker = new MessageIndicationHandlers.UnsoCompleteChecker(this.IsCompleteStatusReportPduModeIndication);
+ this.messages.Add(unsoCompleteChecker1);
+ }
+
+ private IMessageIndicationObject HandleDeliverMemoryIndication(ref string input)
+ {
+ Regex regex = new Regex("\\+CMTI: \"(\\w+)\",(\\d+)");
+ Match match = regex.Match(input);
+ if (match.Success)
+ {
+ string value = match.Groups[1].Value;
+ int num = int.Parse(match.Groups[2].Value);
+ MemoryLocation memoryLocation = new MemoryLocation(value, num);
+ input = input.Remove(match.Index, match.Length);
+ return memoryLocation;
+ }
+ else
+ {
+ throw new ArgumentException("Input string does not contain an SMS-DELIVER memory location indication.");
+ }
+ }
+
+ private IMessageIndicationObject HandleDeliverPduModeIndication(ref string input)
+ {
+ Regex regex = new Regex("\\+CMT: (\\w*),(\\d+)\\r\\n(\\w+)");
+ Match match = regex.Match(input);
+ if (match.Success)
+ {
+ string value = match.Groups[1].Value;
+ int num = int.Parse(match.Groups[2].Value);
+ string str = match.Groups[3].Value;
+ ShortMessage shortMessage = new ShortMessage(value, num, str);
+ input = input.Remove(match.Index, match.Length);
+ return shortMessage;
+ }
+ else
+ {
+ throw new ArgumentException("Input string does not contain an SMS-DELIVER PDU mode indication.");
+ }
+ }
+
+ private IMessageIndicationObject HandleStatusReportMemoryIndication(ref string input)
+ {
+ Regex regex = new Regex("\\+CDSI: \"(\\w+)\",(\\d+)");
+ Match match = regex.Match(input);
+ if (match.Success)
+ {
+ string value = match.Groups[1].Value;
+ int num = int.Parse(match.Groups[2].Value);
+ MemoryLocation memoryLocation = new MemoryLocation(value, num);
+ input = input.Remove(match.Index, match.Length);
+ return memoryLocation;
+ }
+ else
+ {
+ throw new ArgumentException("Input string does not contain an SMS-STATUS-REPORT memory location indication.");
+ }
+ }
+
+ private IMessageIndicationObject HandleStatusReportPduModeIndication(ref string input)
+ {
+ Regex regex = new Regex("\\+CDS: (\\d+)\\r\\n(\\w+)");
+ Match match = regex.Match(input);
+ if (match.Success)
+ {
+ int num = int.Parse(match.Groups[1].Value);
+ string value = match.Groups[2].Value;
+ ShortMessage shortMessage = new ShortMessage(string.Empty, num, value);
+ input = input.Remove(match.Index, match.Length);
+ return shortMessage;
+ }
+ else
+ {
+ throw new ArgumentException("Input string does not contain an SMS-STATUS-REPORT PDU mode indication.");
+ }
+ }
+
+ ///
+ /// Handles an unsolicited message of the specified input string.
+ ///
+ /// The input string to handle, the unsolicited message will be removed
+ /// Receives a textual description of the message, may be empty
+ /// The message indication object generated from the message
+ /// Input string does not match any of the supported
+ /// unsolicited messages
+ public IMessageIndicationObject HandleUnsolicitedMessage(ref string input, out string description)
+ {
+ IMessageIndicationObject messageIndicationObject;
+ List.Enumerator enumerator = this.messages.GetEnumerator();
+ try
+ {
+ while (enumerator.MoveNext())
+ {
+ MessageIndicationHandlers.UnsoMessage current = enumerator.Current;
+ if (!current.IsMatch(input))
+ {
+ continue;
+ }
+ IMessageIndicationObject messageIndicationObject1 = current.Handler(ref input);
+ description = current.Description;
+ messageIndicationObject = messageIndicationObject1;
+ return messageIndicationObject;
+ }
+ throw new ArgumentException("Input string does not match any of the supported unsolicited messages.");
+ }
+ finally
+ {
+ enumerator.Dispose();
+ }
+ return messageIndicationObject;
+ }
+
+ private bool IsCompleteDeliverPduModeIndication(string input)
+ {
+ Regex regex = new Regex("\\+CMT: (\\w*),(\\d+)\\r\\n(\\w+)");
+ Match match = regex.Match(input);
+ if (match.Success)
+ {
+ match.Groups[1].Value;
+ int num = int.Parse(match.Groups[2].Value);
+ string value = match.Groups[3].Value;
+ if (BcdWorker.CountBytes(value) <= 0)
+ {
+ return false;
+ }
+ else
+ {
+ int num1 = BcdWorker.GetByte(value, 0);
+ int num2 = num * 2 + num1 * 2 + 2;
+ return value.Length >= num2;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ private bool IsCompleteStatusReportPduModeIndication(string input)
+ {
+ Regex regex = new Regex("\\+CDS: (\\d+)\\r\\n(\\w+)");
+ Match match = regex.Match(input);
+ if (match.Success)
+ {
+ int num = int.Parse(match.Groups[1].Value);
+ string value = match.Groups[2].Value;
+ if (BcdWorker.CountBytes(value) <= 0)
+ {
+ return false;
+ }
+ else
+ {
+ int num1 = BcdWorker.GetByte(value, 0);
+ int num2 = num * 2 + num1 * 2 + 2;
+ return value.Length >= num2;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public bool IsIncompleteUnsolicitedMessage(string input)
+ {
+ bool flag = false;
+ foreach (MessageIndicationHandlers.UnsoMessage message in this.messages)
+ {
+ if (!message.IsStartMatch(input) || message.IsMatch(input))
+ {
+ continue;
+ }
+ flag = true;
+ break;
+ }
+ return flag;
+ }
+
+ public bool IsUnsolicitedMessage(string input)
+ {
+ bool flag = false;
+ foreach (MessageIndicationHandlers.UnsoMessage message in this.messages)
+ {
+ if (!message.IsMatch(input))
+ {
+ continue;
+ }
+ flag = true;
+ break;
+ }
+ return flag;
+ }
+
+ private delegate bool UnsoCompleteChecker(string input);
+
+ private delegate IMessageIndicationObject UnsoHandler(ref string input);
+
+ private class UnsoMessage
+ {
+ private string pattern;
+
+ private string startPattern;
+
+ private string description;
+
+ private MessageIndicationHandlers.UnsoHandler handler;
+
+ private MessageIndicationHandlers.UnsoCompleteChecker completeChecker;
+
+ public MessageIndicationHandlers.UnsoCompleteChecker CompleteChecker
+ {
+ get
+ {
+ return this.completeChecker;
+ }
+ set
+ {
+ this.completeChecker = value;
+ }
+ }
+
+ public string Description
+ {
+ get
+ {
+ return this.description;
+ }
+ set
+ {
+ this.description = value;
+ }
+ }
+
+ public MessageIndicationHandlers.UnsoHandler Handler
+ {
+ get
+ {
+ return this.handler;
+ }
+ set
+ {
+ this.handler = value;
+ }
+ }
+
+ public string Pattern
+ {
+ get
+ {
+ return this.pattern;
+ }
+ set
+ {
+ this.pattern = value;
+ }
+ }
+
+ public string StartPattern
+ {
+ get
+ {
+ return this.startPattern;
+ }
+ set
+ {
+ this.startPattern = value;
+ }
+ }
+
+ public UnsoMessage(string pattern, MessageIndicationHandlers.UnsoHandler handler)
+ {
+ this.pattern = pattern;
+ this.startPattern = pattern;
+ this.description = string.Empty;
+ this.handler = handler;
+ this.completeChecker = null;
+ }
+
+ public bool IsMatch(string input)
+ {
+ bool flag;
+ if (this.completeChecker == null)
+ {
+ flag = Regex.IsMatch(input, this.pattern);
+ }
+ else
+ {
+ flag = this.completeChecker(input);
+ }
+ return flag;
+ }
+
+ public bool IsStartMatch(string input)
+ {
+ return Regex.IsMatch(input, this.startPattern);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MessageIndicationMode.cs b/GSMCommunication/GsmCommunication/MessageIndicationMode.cs
new file mode 100644
index 0000000..424459a
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MessageIndicationMode.cs
@@ -0,0 +1,30 @@
+///
+/// Specifies the possible modes for for new message indications.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum MessageIndicationMode
+ {
+ ///
+ /// Buffer unsolicited result codes in the TA. If TA result code buffer is full, indications can be
+ /// buffered in some other place or the oldest indications may be discarded and replaced with the new
+ /// received indications.
+ ///
+ DoNotForward,
+ ///
+ /// Discard indication and reject new received message unsolicited result codes when TA-TE link is
+ /// reserved (e.g. in on-line data mode). Otherwise forward them directly to the TE.
+ ///
+ SkipWhenReserved,
+ ///
+ /// Buffer unsolicited result codes in the TA when TA-TE link is reserved (e.g. in on-line data mode) and
+ /// flush them to the TE after reservation. Otherwise forward them directly to the TE.
+ ///
+ BufferAndFlush,
+ ///
+ /// Forward unsolicited result codes directly to the TE. TA-TE link specific inband technique used to
+ /// embed result codes and data when TA is in on-line data mode.
+ ///
+ ForwardAlways
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MessageIndicationSettings.cs b/GSMCommunication/GsmCommunication/MessageIndicationSettings.cs
new file mode 100644
index 0000000..6f25138
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MessageIndicationSettings.cs
@@ -0,0 +1,142 @@
+using System;
+
+///
+/// Specifies the settings for new message notifications.
+///
+namespace GsmComm.GsmCommunication
+{
+ public struct MessageIndicationSettings
+ {
+ private int mode;
+
+ private int mt;
+
+ private int bm;
+
+ private int ds;
+
+ private int bfr;
+
+ ///
+ /// Specifies how the indication buffer should be handled when indications are activated, i.e.
+ /// when is set to any value except .
+ ///
+ ///
+ /// You can use one of the values to set this property.
+ ///
+ public int BufferSetting
+ {
+ get
+ {
+ return this.bfr;
+ }
+ set
+ {
+ this.bfr = value;
+ }
+ }
+
+ ///
+ /// Specifies how new Cell Broadcast messages should be indicated.
+ ///
+ ///
+ /// You can use one of the values to set this property.
+ ///
+ public int CellBroadcastStyle
+ {
+ get
+ {
+ return this.bm;
+ }
+ set
+ {
+ this.bm = value;
+ }
+ }
+
+ ///
+ /// Specifies how new SMS-DELIVER messages should be indicated.
+ ///
+ ///
+ /// You can use one of the values to set this property.
+ ///
+ public int DeliverStyle
+ {
+ get
+ {
+ return this.mt;
+ }
+ set
+ {
+ this.mt = value;
+ }
+ }
+
+ ///
+ /// Specifies the general indication mode.
+ ///
+ ///
+ /// You can use one of the values to set this property.
+ ///
+ public int Mode
+ {
+ get
+ {
+ return this.mode;
+ }
+ set
+ {
+ this.mode = value;
+ }
+ }
+
+ ///
+ /// Specifies how new SMS-STATUS-REPORT messages should be indicated.
+ ///
+ ///
+ /// You can use one of the values to set this property.
+ ///
+ public int StatusReportStyle
+ {
+ get
+ {
+ return this.ds;
+ }
+ set
+ {
+ this.ds = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the structure.
+ ///
+ /// Specifies the general indication mode.
+ /// Specifies how new SMS-DELIVER messages should be indicated.
+ /// Specifies how new Cell Broadcast messages should be indicated.
+ /// Specifies how new SMS-STATUS-REPORT messages should be indicated.
+ /// Specifies how the indication buffer should be handled when indications are activated, i.e.
+ /// when is set to any value except .
+ public MessageIndicationSettings(int mode, int mt, int bm, int ds, int bfr)
+ {
+ this.mode = mode;
+ this.mt = mt;
+ this.bm = bm;
+ this.ds = ds;
+ this.bfr = bfr;
+ }
+
+ ///
+ /// Initializes a new instance of the structure.
+ ///
+ /// Specifies the general indication mode.
+ /// Specifies how new SMS-DELIVER messages should be indicated.
+ /// Specifies how new Cell Broadcast messages should be indicated.
+ /// Specifies how new SMS-STATUS-REPORT messages should be indicated.
+ /// Specifies how the indication buffer should be handled when indications are activated, i.e.
+ /// when is set to any value except .
+ public MessageIndicationSettings(MessageIndicationMode mode, SmsDeliverIndicationStyle mt, CbmIndicationStyle bm, SmsStatusReportIndicationStyle ds, IndicationBufferSetting bfr) : this(mode, mt, bm, ds, bfr)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MessageIndicationSupport.cs b/GSMCommunication/GsmCommunication/MessageIndicationSupport.cs
new file mode 100644
index 0000000..7ddae21
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MessageIndicationSupport.cs
@@ -0,0 +1,225 @@
+using System;
+using System.Collections;
+using System.Text.RegularExpressions;
+
+///
+/// Contains information about the supported new message indications of the phone.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class MessageIndicationSupport
+ {
+ private string mode;
+
+ private string deliver;
+
+ private string cellBroadcast;
+
+ private string statusReport;
+
+ private string buffer;
+
+ ///
+ /// Gets a string representation of the supported buffer handling settings.
+ ///
+ public string BufferHandling
+ {
+ get
+ {
+ return this.buffer;
+ }
+ }
+
+ ///
+ /// Gets a string representation of the supported cell broadcast indication styles.
+ ///
+ public string CellBroadcastStyles
+ {
+ get
+ {
+ return this.cellBroadcast;
+ }
+ }
+
+ ///
+ /// Gets a string representation of the supported deliver indication modes.
+ ///
+ public string DeliverStyles
+ {
+ get
+ {
+ return this.deliver;
+ }
+ }
+
+ ///
+ /// Gets a string representation of the supported indication modes.
+ ///
+ public string Modes
+ {
+ get
+ {
+ return this.mode;
+ }
+ }
+
+ ///
+ /// Gets a string representation of the supported status report indication styles.
+ ///
+ public string StatusReportStyles
+ {
+ get
+ {
+ return this.statusReport;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A string representation of the phone's supported indication modes
+ /// A string representation of the phones's supported standard SMS (SMS-DELIVER) styles
+ /// A string representation of the phones's supported cell broadcast styles
+ /// The phones's supported status report (SMS-STATUS-REPORT) styles
+ /// The phones's supported buffer handling settings
+ public MessageIndicationSupport(string mode, string deliver, string cellBroadcast, string statusReport, string buffer)
+ {
+ this.mode = mode;
+ this.deliver = deliver;
+ this.cellBroadcast = cellBroadcast;
+ this.statusReport = statusReport;
+ this.buffer = buffer;
+ }
+
+ private ArrayList ParseArrayAsString(string s)
+ {
+ ArrayList arrayLists = new ArrayList();
+ Regex regex = new Regex("(?:(\\d+),?)+");
+ Match match = regex.Match(s);
+ if (match.Success)
+ {
+ foreach (Capture capture in match.Groups[1].Captures)
+ {
+ arrayLists.Add(int.Parse(capture.Value));
+ }
+ }
+ Regex regex1 = new Regex("(\\d+)-(\\d+)");
+ Match match1 = regex1.Match(s);
+ if (match1.Success)
+ {
+ int num = int.Parse(match1.Groups[1].Value);
+ int num1 = int.Parse(match1.Groups[2].Value);
+ for (int i = num; i <= num1; i++)
+ {
+ arrayLists.Add(i);
+ }
+ }
+ return arrayLists;
+ }
+
+ ///
+ /// Checks if a specific buffer handling setting is supported.
+ ///
+ /// The setting to check
+ /// true if the setting is supported, false otherwise.
+ public bool SupportsBufferSetting(int setting)
+ {
+ ArrayList arrayLists = this.ParseArrayAsString(this.buffer);
+ return arrayLists.Contains(setting);
+ }
+
+ ///
+ /// Checks if a specific buffer handling setting is supported.
+ ///
+ /// The setting to check
+ /// true if the setting is supported, false otherwise.
+ public bool SupportsBufferSetting(IndicationBufferSetting setting)
+ {
+ return this.SupportsBufferSetting(setting);
+ }
+
+ ///
+ /// Checks if a specific cell broadcast indication style is supported.
+ ///
+ /// The style to check
+ /// true if the style is supported, false otherwise.
+ public bool SupportsCellBroadcastStyle(int style)
+ {
+ ArrayList arrayLists = this.ParseArrayAsString(this.cellBroadcast);
+ return arrayLists.Contains(style);
+ }
+
+ ///
+ /// Checks if a specific cell broadcast indication style is supported.
+ ///
+ /// The style to check
+ /// true if the style is supported, false otherwise.
+ public bool SupportsCellBroadcastStyle(CbmIndicationStyle style)
+ {
+ return this.SupportsCellBroadcastStyle(style);
+ }
+
+ ///
+ /// Checks if a specific SMS-DELIVER indication style is supported.
+ ///
+ /// The style to check
+ /// true if the style is supported, false otherwise.
+ public bool SupportsDeliverStyle(int style)
+ {
+ ArrayList arrayLists = this.ParseArrayAsString(this.deliver);
+ return arrayLists.Contains(style);
+ }
+
+ ///
+ /// Checks if a specific SMS-DELIVER indication style is supported.
+ ///
+ /// The style to check
+ /// true if the style is supported, false otherwise.
+ public bool SupportsDeliverStyle(SmsDeliverIndicationStyle style)
+ {
+ return this.SupportsDeliverStyle(style);
+ }
+
+ ///
+ /// Checks if a specific indication mode is supported.
+ ///
+ /// The mode to check
+ /// true if the mode is supported, false otherwise.
+ public bool SupportsMode(int mode)
+ {
+ ArrayList arrayLists = this.ParseArrayAsString(this.mode);
+ return arrayLists.Contains(mode);
+ }
+
+ ///
+ /// Checks if a specific indication mode is supported.
+ ///
+ /// The mode to check
+ /// true if the mode is supported, false otherwise.
+ public bool SupportsMode(MessageIndicationMode mode)
+ {
+ return this.SupportsMode(mode);
+ }
+
+ ///
+ /// Checks if a specific status report (SMS-STATUS-REPORT) indication style is supported.
+ ///
+ /// The style to check
+ /// true if the style is supported, false otherwise.
+ public bool SupportsStatusReportStyle(int style)
+ {
+ ArrayList arrayLists = this.ParseArrayAsString(this.statusReport);
+ return arrayLists.Contains(style);
+ }
+
+ ///
+ /// Checks if a specific status report (SMS-STATUS-REPORT) indication style is supported.
+ ///
+ /// The style to check
+ /// true if the style is supported, false otherwise.
+ public bool SupportsStatusReportStyle(SmsStatusReportIndicationStyle style)
+ {
+ return this.SupportsStatusReportStyle(style);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MessageMemoryStatus.cs b/GSMCommunication/GsmCommunication/MessageMemoryStatus.cs
new file mode 100644
index 0000000..840effd
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MessageMemoryStatus.cs
@@ -0,0 +1,79 @@
+///
+/// Contains status information of all message memories.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class MessageMemoryStatus
+ {
+ private MemoryStatus readStorage;
+
+ private MemoryStatus writeStorage;
+
+ private MemoryStatus receiveStorage;
+
+ ///
+ /// Gets or sets the status of the current read storage.
+ ///
+ public MemoryStatus ReadStorage
+ {
+ get
+ {
+ return this.readStorage;
+ }
+ set
+ {
+ this.readStorage = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the status of the current receive storage.
+ ///
+ public MemoryStatus ReceiveStorage
+ {
+ get
+ {
+ return this.receiveStorage;
+ }
+ set
+ {
+ this.receiveStorage = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the status of the current write storage.
+ ///
+ public MemoryStatus WriteStorage
+ {
+ get
+ {
+ return this.writeStorage;
+ }
+ set
+ {
+ this.writeStorage = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public MessageMemoryStatus()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified parameters.
+ ///
+ /// Status of the current read storage
+ /// Status of the current write storage
+ /// Status of the current receive storage
+ public MessageMemoryStatus(MemoryStatus readStorage, MemoryStatus writeStorage, MemoryStatus receiveStorage)
+ {
+ this.readStorage = readStorage;
+ this.writeStorage = writeStorage;
+ this.receiveStorage = receiveStorage;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MessageReceivedEventArgs.cs b/GSMCommunication/GsmCommunication/MessageReceivedEventArgs.cs
new file mode 100644
index 0000000..0e12289
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MessageReceivedEventArgs.cs
@@ -0,0 +1,30 @@
+///
+/// Provides data for the events.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class MessageReceivedEventArgs
+ {
+ private IMessageIndicationObject indicationObject;
+
+ ///
+ /// The object that indicates a new received message.
+ ///
+ public IMessageIndicationObject IndicationObject
+ {
+ get
+ {
+ return this.indicationObject;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The object that indicates a new received message.
+ public MessageReceivedEventArgs(IMessageIndicationObject obj)
+ {
+ this.indicationObject = obj;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MessageReceivedEventHandler.cs b/GSMCommunication/GsmCommunication/MessageReceivedEventHandler.cs
new file mode 100644
index 0000000..0d7857f
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MessageReceivedEventHandler.cs
@@ -0,0 +1,11 @@
+using System;
+
+///
+/// The method that handles the event.
+///
+/// The origin of the event.
+/// The arguments containing more information.
+namespace GsmComm.GsmCommunication
+{
+ public delegate void MessageReceivedEventHandler(object sender, MessageReceivedEventArgs e);
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MessageStorageInfo.cs b/GSMCommunication/GsmCommunication/MessageStorageInfo.cs
new file mode 100644
index 0000000..5711932
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MessageStorageInfo.cs
@@ -0,0 +1,19 @@
+using System;
+
+///
+/// Provides a structure that contains details about supported message storages.
+///
+namespace GsmComm.GsmCommunication
+{
+ public struct MessageStorageInfo
+ {
+ /// Specifies the storages that can be used for reading and deleting.
+ public string[] ReadStorages;
+
+ /// Speicifies the storages that can be used for writing and sending.
+ public string[] WriteStorages;
+
+ /// Specifies the storages that can be used as the preferred receive storage.
+ public string[] ReceiveStorages;
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/MoreMessagesMode.cs b/GSMCommunication/GsmCommunication/MoreMessagesMode.cs
new file mode 100644
index 0000000..d89e352
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/MoreMessagesMode.cs
@@ -0,0 +1,23 @@
+///
+/// Contains the possible modes for the AT+CMMS command to set the high-speed SMS sending behaviour.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum MoreMessagesMode
+ {
+ /// The function is disabled, the SMS link is not kept open.
+ Disabled,
+ ///
+ /// Keep enabled until the time between the response of the latest message send command (+CMGS, +CMSS, etc.)
+ /// and the next send command exceeds 1-5 seconds (the exact value is up to ME implementation), then ME shall
+ /// close the link and TA switches the mode automatically back to disabled (0).
+ ///
+ Temporary,
+ ///
+ /// Enables (if the time between the response of the latest message send command and the next send command
+ /// exceeds 1-5 seconds (the exact value is up to ME implementation), ME shall close the link but TA shall
+ /// not switch automatically back to disabled (0)).
+ ///
+ Permanent
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/OperatorFormat.cs b/GSMCommunication/GsmCommunication/OperatorFormat.cs
new file mode 100644
index 0000000..1f95fba
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/OperatorFormat.cs
@@ -0,0 +1,18 @@
+///
+/// Contains the possible formats in which a network operator can be returned.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum OperatorFormat
+ {
+ /// Long format, alphanumeric
+ LongFormatAlphanumeric,
+ /// Short format, alphanumeric
+ ShortFormatAlphanumeric,
+ ///
+ /// Numeric format, GSM Location Area Identification number (BCD encoded, 3 digits country code,
+ /// 2 digits network code)
+ ///
+ Numeric
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/OperatorInfo.cs b/GSMCommunication/GsmCommunication/OperatorInfo.cs
new file mode 100644
index 0000000..287f096
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/OperatorInfo.cs
@@ -0,0 +1,80 @@
+using System;
+
+///
+/// Contains information about a GSM network operator.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class OperatorInfo
+ {
+ private OperatorFormat format;
+
+ private string theOperator;
+
+ private string accessTechnology;
+
+ ///
+ /// Gets the access technology registered to.
+ ///
+ /// This is optional, as it is only useful for terminals capable to register to more than
+ /// one access technology.
+ public string AccessTechnology
+ {
+ get
+ {
+ return this.accessTechnology;
+ }
+ }
+
+ ///
+ /// Gets the format in which is specified in.
+ ///
+ public OperatorFormat Format
+ {
+ get
+ {
+ return this.format;
+ }
+ }
+
+ ///
+ /// Gets the operator in the format specified by .
+ ///
+ public string TheOperator
+ {
+ get
+ {
+ return this.theOperator;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The format in which theOperator is specified in. See
+ /// for a list of possible values.
+ ///
+ /// The operator in the format specified by format
+ public OperatorInfo(OperatorFormat format, string theOperator)
+ {
+ this.format = format;
+ this.theOperator = theOperator;
+ this.accessTechnology = string.Empty;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The format in which theOperator is specified in. See
+ /// for a list of possible values.
+ ///
+ /// The operator in the format specified by format
+ /// The access technology registered to.
+ public OperatorInfo(OperatorFormat format, string theOperator, string accessTechnology)
+ {
+ this.format = format;
+ this.theOperator = theOperator;
+ this.accessTechnology = accessTechnology;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/OperatorInfo2.cs b/GSMCommunication/GsmCommunication/OperatorInfo2.cs
new file mode 100644
index 0000000..b6b291c
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/OperatorInfo2.cs
@@ -0,0 +1,121 @@
+using System;
+
+///
+/// Contains information about a GSM network operator.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class OperatorInfo2
+ {
+ private OperatorStatus stat;
+
+ private string longAlpha;
+
+ private string shortAlpha;
+
+ private string numeric;
+
+ private string act;
+
+ ///
+ /// Gets the access technology the operator uses.
+ ///
+ /// This is optional, as it is only useful for terminals capable to register to more than
+ /// one access technology.
+ public string AccessTechnology
+ {
+ get
+ {
+ return this.act;
+ }
+ }
+
+ ///
+ /// Gets the operator name in long alphanumeric format.
+ ///
+ /// If the phone does not support this format, the string will be empty.
+ public string LongAlphanumeric
+ {
+ get
+ {
+ return this.longAlpha;
+ }
+ }
+
+ ///
+ /// Gets the operator in numeric format.
+ ///
+ /// If the phone does not support this format, the string will be empty.
+ public string Numeric
+ {
+ get
+ {
+ return this.numeric;
+ }
+ }
+
+ ///
+ /// Gets the operator name in short alphanumic format.
+ ///
+ /// If the phone does not support this format, the string will be empty.
+ public string ShortAlphanumeric
+ {
+ get
+ {
+ return this.shortAlpha;
+ }
+ }
+
+ ///
+ /// Gets the availability of the operator.
+ ///
+ public OperatorStatus Status
+ {
+ get
+ {
+ return this.stat;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The operator availability
+ /// The operator name in long alphanumeric format
+ /// The operator name in short alphanumeric format
+ /// The operator in numeric format
+ /// If the phone does not support one of the formats longAlphanumeric,
+ /// shortAlphanumeric, numeric, the curresponding string is left empty.
+ public OperatorInfo2(OperatorStatus status, string longAlphanumeric, string shortAlphanumeric, string numeric)
+ {
+ this.stat = status;
+ this.longAlpha = longAlphanumeric;
+ this.shortAlpha = shortAlphanumeric;
+ this.numeric = numeric;
+ this.act = string.Empty;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The operator availability
+ /// The operator name in long alphanumeric format
+ /// The operator name in short alphanumeric format
+ /// The operator in numeric format
+ /// The access technology the operator uses.
+ ///
+ /// If the phone does not support one of the formats longAlphanumeric,
+ /// shortAlphanumeric, numeric, the curresponding string is left empty.
+ /// The accessTechnology is optional, as it is only useful for terminals capable
+ /// to register to more than one access technology.
+ ///
+ public OperatorInfo2(OperatorStatus status, string longAlphanumeric, string shortAlphanumeric, string numeric, string accessTechnology)
+ {
+ this.stat = status;
+ this.longAlpha = longAlphanumeric;
+ this.shortAlpha = shortAlphanumeric;
+ this.numeric = numeric;
+ this.act = accessTechnology;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/OperatorSelectionMode.cs b/GSMCommunication/GsmCommunication/OperatorSelectionMode.cs
new file mode 100644
index 0000000..54fd6c1
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/OperatorSelectionMode.cs
@@ -0,0 +1,25 @@
+///
+/// Contains the possible values for the operator selection mode.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum OperatorSelectionMode
+ {
+ ///
+ /// The phone selects the operator automatically.
+ ///
+ Automatic = 0,
+ ///
+ /// A specific operator is selected. The phone does not attempt to select the operator automatically.
+ ///
+ Manual = 1,
+ ///
+ /// The phone is not registered to the network.
+ ///
+ Deregistered = 2,
+ ///
+ /// If manual selection fails, automatic mode is entered.
+ ///
+ ManualAutomatic = 4
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/OperatorStatus.cs b/GSMCommunication/GsmCommunication/OperatorStatus.cs
new file mode 100644
index 0000000..c70f816
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/OperatorStatus.cs
@@ -0,0 +1,17 @@
+///
+/// Conatins the operator availability values.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum OperatorStatus
+ {
+ /// The operator status is unknown.
+ Unknown,
+ /// The operator is available for selection.
+ Available,
+ /// Denotes that this is the currently selected operator.
+ Current,
+ /// The phone must not connect to this operator.
+ Forbidden
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/PhoneMessageStatus.cs b/GSMCommunication/GsmCommunication/PhoneMessageStatus.cs
new file mode 100644
index 0000000..12ae1a4
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/PhoneMessageStatus.cs
@@ -0,0 +1,19 @@
+///
+/// The message status to request from the phone or the actual type.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum PhoneMessageStatus
+ {
+ /// The message was received, but not yet read.
+ ReceivedUnread,
+ /// The message was received and has been read.
+ ReceivedRead,
+ /// The message was stored, but had not been sent yet.
+ StoredUnsent,
+ /// The message was stored and sent.
+ StoredSent,
+ /// Specifies all status.
+ All
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/PhoneNumberService.cs b/GSMCommunication/GsmCommunication/PhoneNumberService.cs
new file mode 100644
index 0000000..8c4dc85
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/PhoneNumberService.cs
@@ -0,0 +1,21 @@
+///
+/// Contains services related to a subscriber phone number.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum PhoneNumberService
+ {
+ /// Asynchronous modem
+ AsynchronousModem,
+ /// Synchronous modem
+ SynchronousModem,
+ /// PAD Access (asynchronous)
+ PadAccess,
+ /// Packet Access (synchronous)
+ PacketAccess,
+ /// Voice
+ Voice,
+ /// Fax
+ Fax
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/PhoneStorageType.cs b/GSMCommunication/GsmCommunication/PhoneStorageType.cs
new file mode 100644
index 0000000..2a05fb4
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/PhoneStorageType.cs
@@ -0,0 +1,20 @@
+using System;
+
+///
+/// Lists common storage types.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class PhoneStorageType
+ {
+ /// SIM storage
+ public const string Sim = "SM";
+
+ /// Phone storage
+ public const string Phone = "ME";
+
+ public PhoneStorageType()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/PhonebookEntry.cs b/GSMCommunication/GsmCommunication/PhonebookEntry.cs
new file mode 100644
index 0000000..b1059dc
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/PhonebookEntry.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Xml.Serialization;
+
+///
+/// Represents a phonebook entry.
+///
+namespace GsmComm.GsmCommunication
+{
+ [Serializable]
+ [XmlInclude(typeof(PhonebookEntryWithStorage))]
+ public class PhonebookEntry
+ {
+ private int index;
+
+ private string number;
+
+ private int type;
+
+ private string text;
+
+ ///
+ /// The index where the entry is saved in the phone.
+ ///
+ [XmlAttribute]
+ public int Index
+ {
+ get
+ {
+ return this.index;
+ }
+ set
+ {
+ this.index = value;
+ }
+ }
+
+ ///
+ /// The phone number.
+ ///
+ [XmlAttribute]
+ public string Number
+ {
+ get
+ {
+ return this.number;
+ }
+ set
+ {
+ this.number = value;
+ }
+ }
+
+ ///
+ /// The text (name) associated with the .
+ ///
+ [XmlAttribute]
+ public string Text
+ {
+ get
+ {
+ return this.text;
+ }
+ set
+ {
+ this.text = value;
+ }
+ }
+
+ ///
+ /// The 's address type.
+ ///
+ [XmlAttribute]
+ public int Type
+ {
+ get
+ {
+ return this.type;
+ }
+ set
+ {
+ this.type = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PhonebookEntry()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class using the specified values.
+ ///
+ /// The index where the entry is saved in the phone.
+ /// The phone number.
+ /// The 's address type.
+ /// The text (name) associated with the .
+ public PhonebookEntry(int index, string number, int type, string text)
+ {
+ this.index = index;
+ this.number = number;
+ this.type = type;
+ this.text = text;
+ }
+
+ ///
+ /// Initializes a new instance of the class to copy an existing .
+ ///
+ /// The entry to copy.
+ public PhonebookEntry(PhonebookEntry entry)
+ {
+ this.index = entry.Index;
+ this.number = entry.Number;
+ this.type = entry.type;
+ this.text = entry.Text;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/PhonebookEntryWithStorage.cs b/GSMCommunication/GsmCommunication/PhonebookEntryWithStorage.cs
new file mode 100644
index 0000000..b11bdb2
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/PhonebookEntryWithStorage.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Xml.Serialization;
+
+///
+/// Represents a extended by the storage value.
+///
+namespace GsmComm.GsmCommunication
+{
+ [Serializable]
+ public class PhonebookEntryWithStorage : PhonebookEntry
+ {
+ private string storage;
+
+ ///
+ /// The storage the entry was read from.
+ ///
+ [XmlAttribute]
+ public string Storage
+ {
+ get
+ {
+ return this.storage;
+ }
+ set
+ {
+ this.storage = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PhonebookEntryWithStorage()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class using the specified values.
+ ///
+ /// The phonebook entry
+ /// The storage the entry was read from.
+ public PhonebookEntryWithStorage(PhonebookEntry entry, string storage) : base(entry)
+ {
+ this.storage = storage;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/PinStatus.cs b/GSMCommunication/GsmCommunication/PinStatus.cs
new file mode 100644
index 0000000..0660784
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/PinStatus.cs
@@ -0,0 +1,51 @@
+///
+/// Lists the possible PIN states of the phone.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum PinStatus
+ {
+ /// Phone does not wait for any password
+ Ready,
+ /// Phone is waiting for SIM PIN to be given
+ SimPin,
+ /// Phone is waiting for SIM PUK to be given
+ SimPuk,
+ /// Phone is waiting for phone to SIM card password to be given
+ PhoneToSimPin,
+ /// Phone is waiting for phone-to-very first SIM card password to be given
+ PhoneToFirstSimPin,
+ /// Phone is waiting for phone-to-very first SIM card unblocking password to be given
+ PhoneToFirstSimPuk,
+ ///
+ /// Phone is waiting for SIM PIN2 to be given (this status should be expected to be returned
+ /// by phones only when the last executed command resulted in PIN2 authentication failure (i.e. device
+ /// error 17); if PIN2 is not entered right after the failure, the phone should be expected not to block
+ /// its operation)
+ ///
+ SimPin2,
+ ///
+ /// Phone is waiting for SIM PUK2 to be given (this status should be expected to be returned
+ /// by phones only when the last executed command resulted in PUK2 authentication failure (i.e. device
+ /// error 18); if PUK2 is not entered right after the failure, the phone should be expected not to block
+ /// its operation)
+ ///
+ SimPuk2,
+ /// Phone is waiting for network personalization password to be given
+ PhoneToNetworkPin,
+ /// Phone is waiting for network personalization unblocking password to be given
+ PhoneToNetworkPuk,
+ /// Phone is waiting for network subset personalization password to be given
+ PhoneToNetworkSubsetPin,
+ /// Phone is waiting for network subset personalization unblocking password to be given
+ PhoneToNetworkSubsetPuk,
+ /// Phone is waiting for service provider personalization password to be given
+ PhoneToServiceProviderPin,
+ /// Phone is waiting for service provider personalization unblocking password to be given
+ PhoneToServiceProviderPuk,
+ /// Phone is waiting for corporate personalization password to be given
+ PhoneToCorporatePin,
+ /// Phone is waiting for corporate personalization unblocking password to be given
+ PhoneToCorporatePuk
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/ProgressEventArgs.cs b/GSMCommunication/GsmCommunication/ProgressEventArgs.cs
new file mode 100644
index 0000000..73656a6
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/ProgressEventArgs.cs
@@ -0,0 +1,32 @@
+using System;
+
+///
+/// Provides data for the and events.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class ProgressEventArgs : EventArgs
+ {
+ private int progress;
+
+ ///
+ /// Get the current progress value.
+ ///
+ public int Progress
+ {
+ get
+ {
+ return this.progress;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the event args.
+ ///
+ /// The current progress value.
+ public ProgressEventArgs(int progress)
+ {
+ this.progress = progress;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/ProgressEventHandler.cs b/GSMCommunication/GsmCommunication/ProgressEventHandler.cs
new file mode 100644
index 0000000..1e44c83
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/ProgressEventHandler.cs
@@ -0,0 +1,11 @@
+using System;
+
+///
+/// The method that handles the and the events.
+///
+/// The origin of the event.
+/// The arguments containing more information.
+namespace GsmComm.GsmCommunication
+{
+ public delegate void ProgressEventHandler(object sender, ProgressEventArgs e);
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/SerialPortFixer.cs b/GSMCommunication/GsmCommunication/SerialPortFixer.cs
new file mode 100644
index 0000000..b8316d9
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/SerialPortFixer.cs
@@ -0,0 +1,213 @@
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace GsmComm.GsmCommunication
+{
+ internal class SerialPortFixer : IDisposable
+ {
+ private const int DcbFlagAbortOnError = 14;
+
+ private const int CommStateRetries = 10;
+
+ private SafeFileHandle m_Handle;
+
+ private SerialPortFixer(string portName)
+ {
+ if (portName == null || !portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
+ {
+ throw new ArgumentException("Invalid Serial Port", "portName");
+ }
+ else
+ {
+ SafeFileHandle safeFileHandle = SerialPortFixer.CreateFile(string.Concat("\\\\.\\", portName), -1073741824, 0, IntPtr.Zero, 3, 1073741824, IntPtr.Zero);
+ if (safeFileHandle.IsInvalid)
+ {
+ SerialPortFixer.WinIoError();
+ }
+ try
+ {
+ int fileType = SerialPortFixer.GetFileType(safeFileHandle);
+ if (fileType == 2 || fileType == 0)
+ {
+ this.m_Handle = safeFileHandle;
+ this.InitializeDcb();
+ }
+ else
+ {
+ throw new ArgumentException("Invalid Serial Port", "portName");
+ }
+ }
+ catch
+ {
+ safeFileHandle.Close();
+ this.m_Handle = null;
+ throw;
+ }
+ return;
+ }
+ }
+
+ [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
+ private static extern bool ClearCommError(SafeFileHandle hFile, ref int lpErrors, ref SerialPortFixer.Comstat lpStat);
+
+ [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
+ private static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr securityAttrs, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
+
+ public void Dispose()
+ {
+ if (this.m_Handle != null)
+ {
+ this.m_Handle.Close();
+ this.m_Handle = null;
+ }
+ }
+
+ public static void Execute(string portName)
+ {
+ using (SerialPortFixer serialPortFixer = new SerialPortFixer(portName))
+ {
+ }
+ }
+
+ [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
+ private static extern int FormatMessage(int dwFlags, HandleRef lpSource, int dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr arguments);
+
+ [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
+ private static extern bool GetCommState(SafeFileHandle hFile, ref SerialPortFixer.Dcb lpDcb);
+
+ private void GetCommStateNative(ref SerialPortFixer.Dcb lpDcb)
+ {
+ int num = 0;
+ SerialPortFixer.Comstat comstat = new SerialPortFixer.Comstat();
+ int num1 = 0;
+ while (num1 < 10)
+ {
+ if (!SerialPortFixer.ClearCommError(this.m_Handle, ref num, ref comstat))
+ {
+ SerialPortFixer.WinIoError();
+ }
+ if (!SerialPortFixer.GetCommState(this.m_Handle, ref lpDcb))
+ {
+ if (num1 == 9)
+ {
+ SerialPortFixer.WinIoError();
+ }
+ num1++;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
+ [DllImport("kernel32.dll", CharSet=CharSet.None)]
+ private static extern int GetFileType(SafeFileHandle hFile);
+
+ private static string GetMessage(int errorCode)
+ {
+ StringBuilder stringBuilder = new StringBuilder(512);
+ if (SerialPortFixer.FormatMessage(12800, new HandleRef(null, IntPtr.Zero), errorCode, 0, stringBuilder, stringBuilder.Capacity, IntPtr.Zero) == 0)
+ {
+ return "Unknown Error";
+ }
+ else
+ {
+ return stringBuilder.ToString();
+ }
+ }
+
+ private void InitializeDcb()
+ {
+ SerialPortFixer.Dcb flags = new SerialPortFixer.Dcb();
+ this.GetCommStateNative(ref flags);
+ flags.Flags = flags.Flags & -16385;
+ this.SetCommStateNative(ref flags);
+ }
+
+ private static int MakeHrFromErrorCode(int errorCode)
+ {
+ return -2147024896 | errorCode;
+ }
+
+ [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
+ private static extern bool SetCommState(SafeFileHandle hFile, ref SerialPortFixer.Dcb lpDcb);
+
+ private void SetCommStateNative(ref SerialPortFixer.Dcb lpDcb)
+ {
+ int num = 0;
+ SerialPortFixer.Comstat comstat = new SerialPortFixer.Comstat();
+ int num1 = 0;
+ while (num1 < 10)
+ {
+ if (!SerialPortFixer.ClearCommError(this.m_Handle, ref num, ref comstat))
+ {
+ SerialPortFixer.WinIoError();
+ }
+ if (!SerialPortFixer.SetCommState(this.m_Handle, ref lpDcb))
+ {
+ if (num1 == 9)
+ {
+ SerialPortFixer.WinIoError();
+ }
+ num1++;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
+ private static void WinIoError()
+ {
+ int lastWin32Error = Marshal.GetLastWin32Error();
+ throw new IOException(SerialPortFixer.GetMessage(lastWin32Error), SerialPortFixer.MakeHrFromErrorCode(lastWin32Error));
+ }
+
+ private struct Comstat
+ {
+ public readonly uint Flags;
+
+ public readonly uint cbInQue;
+
+ public readonly uint cbOutQue;
+ }
+
+ private struct Dcb
+ {
+ public readonly uint DCBlength;
+
+ public readonly uint BaudRate;
+
+ public uint Flags;
+
+ public readonly ushort wReserved;
+
+ public readonly ushort XonLim;
+
+ public readonly ushort XoffLim;
+
+ public readonly byte ByteSize;
+
+ public readonly byte Parity;
+
+ public readonly byte StopBits;
+
+ public readonly byte XonChar;
+
+ public readonly byte XoffChar;
+
+ public readonly byte ErrorChar;
+
+ public readonly byte EofChar;
+
+ public readonly byte EvtChar;
+
+ public readonly ushort wReserved1;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/ShortMessage.cs b/GSMCommunication/GsmCommunication/ShortMessage.cs
new file mode 100644
index 0000000..bc5f431
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/ShortMessage.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Xml.Serialization;
+
+///
+/// Represents a short message in undecoded PDU format.
+///
+namespace GsmComm.GsmCommunication
+{
+ [Serializable]
+ [XmlInclude(typeof(ShortMessageFromPhone))]
+ public class ShortMessage : IMessageIndicationObject
+ {
+ private string alpha;
+
+ private int length;
+
+ private string data;
+
+ ///
+ /// The alphabet in which the message is encoded.
+ ///
+ [XmlAttribute]
+ public string Alpha
+ {
+ get
+ {
+ return this.alpha;
+ }
+ set
+ {
+ this.alpha = value;
+ }
+ }
+
+ ///
+ /// The actual message.
+ ///
+ [XmlElement]
+ public string Data
+ {
+ get
+ {
+ return this.data;
+ }
+ set
+ {
+ this.data = value;
+ }
+ }
+
+ ///
+ /// The length of the message. In PDU format, this is the actual length without the SMSC header.
+ ///
+ [XmlAttribute]
+ public int Length
+ {
+ get
+ {
+ return this.length;
+ }
+ set
+ {
+ this.length = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ShortMessage()
+ {
+ this.alpha = string.Empty;
+ this.length = 0;
+ this.data = string.Empty;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The alphabet in which the message is encoded.
+ /// The length of the data.
+ /// The message.
+ public ShortMessage(string alpha, int length, string data)
+ {
+ this.Alpha = alpha;
+ this.Length = length;
+ this.Data = data;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/ShortMessageFromPhone.cs b/GSMCommunication/GsmCommunication/ShortMessageFromPhone.cs
new file mode 100644
index 0000000..e94bb1d
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/ShortMessageFromPhone.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Xml.Serialization;
+
+///
+/// Represents a short message read from the phone in undecoded PDU format.
+///
+namespace GsmComm.GsmCommunication
+{
+ [Serializable]
+ public class ShortMessageFromPhone : ShortMessage
+ {
+ private int index;
+
+ private int status;
+
+ ///
+ /// The index of the message.
+ ///
+ [XmlAttribute]
+ public int Index
+ {
+ get
+ {
+ return this.index;
+ }
+ set
+ {
+ this.index = value;
+ }
+ }
+
+ ///
+ /// The message status (e.g. read, unread, etc.)
+ ///
+ [XmlAttribute]
+ public int Status
+ {
+ get
+ {
+ return this.status;
+ }
+ set
+ {
+ this.status = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ShortMessageFromPhone()
+ {
+ this.index = 0;
+ this.status = 0;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The index where the message is saved in the device in the currently active storage.
+ /// The message status (e.g. read or unread)
+ /// The alphabet in which the message is encoded.
+ /// The length of the data.
+ /// The actual message.
+ /// The object contains all data returned by the phone.
+ ///
+ public ShortMessageFromPhone(int index, int status, string alpha, int length, string data) : base(alpha, length, data)
+ {
+ this.Index = index;
+ this.Status = status;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/SignalQualityInfo.cs b/GSMCommunication/GsmCommunication/SignalQualityInfo.cs
new file mode 100644
index 0000000..612e8e5
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/SignalQualityInfo.cs
@@ -0,0 +1,51 @@
+using System;
+
+///
+/// Contains the signal strength as calculcated by the ME.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class SignalQualityInfo
+ {
+ private int signalStrength;
+
+ private int bitErrorRate;
+
+ ///
+ /// Gets the bit error rate.
+ ///
+ /// Usually 99 is used if the bit error rate is not known.
+ public int BitErrorRate
+ {
+ get
+ {
+ return this.bitErrorRate;
+ }
+ }
+
+ ///
+ /// Gets the signal strength.
+ ///
+ /// Usual value is an RSSI value in the range of 0 (no signal) to 31 (best signal),
+ /// 99 if not known.
+ public int SignalStrength
+ {
+ get
+ {
+ return this.signalStrength;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The signal strength, usual as an RSSI value in the range of 0 (no signal)
+ /// to 31 (best signal), 99 if not known.
+ /// The bit error rate, 99 if not known.
+ public SignalQualityInfo(int signalStrength, int bitErrorRate)
+ {
+ this.signalStrength = signalStrength;
+ this.bitErrorRate = bitErrorRate;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/SmsDeliverIndicationStyle.cs b/GSMCommunication/GsmCommunication/SmsDeliverIndicationStyle.cs
new file mode 100644
index 0000000..034bf21
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/SmsDeliverIndicationStyle.cs
@@ -0,0 +1,30 @@
+///
+/// Specifies the possible indication styles for new SMS-DELIVER messages.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum SmsDeliverIndicationStyle
+ {
+ ///
+ /// No SMS-DELIVER indications are routed to the TE.
+ ///
+ Disabled,
+ ///
+ /// If SMS-DELIVER is stored into ME/TA, indication of the memory location is routed to the TE.
+ ///
+ RouteMemoryLocation,
+ ///
+ /// SMS-DELIVERs (except class 2 messages and messages in the message waiting indication
+ /// group (store message)) are routed directly to the TE. Depending on the currently selected message
+ /// format, this is done in either PDU or text mode.
+ /// Class 2 messages and messages in the message waiting indication group (store message) result in
+ /// the same indication as with .
+ ///
+ RouteMessage,
+ ///
+ /// Class 3 SMS-DELIVERs are routed directly to TE with the same format as with .
+ /// Messages of other data coding schemes result in indication as with .
+ ///
+ RouteSpecial
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/SmsStatusReportIndicationStyle.cs b/GSMCommunication/GsmCommunication/SmsStatusReportIndicationStyle.cs
new file mode 100644
index 0000000..66a01e1
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/SmsStatusReportIndicationStyle.cs
@@ -0,0 +1,22 @@
+///
+/// Specifies the possible indication settings for new status report messages.
+///
+namespace GsmComm.GsmCommunication
+{
+ public enum SmsStatusReportIndicationStyle
+ {
+ ///
+ /// No SMS-STATUS-REPORTs are routed to the TE.
+ ///
+ Disabled,
+ ///
+ /// SMS-STATUS-REPORTs are routed to the TE using unsolicited result code. Depending on the currently
+ /// selected message format, this is done in either PDU or text mode.
+ ///
+ RouteMessage,
+ ///
+ /// If SMS-STATUS-REPORT is stored into ME/TA, indication of the memory location is routed to the TE.
+ ///
+ RouteMemoryLocation
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/GsmCommunication/SubscriberInfo.cs b/GSMCommunication/GsmCommunication/SubscriberInfo.cs
new file mode 100644
index 0000000..6db8b07
--- /dev/null
+++ b/GSMCommunication/GsmCommunication/SubscriberInfo.cs
@@ -0,0 +1,133 @@
+using System;
+
+///
+/// Contains network subscriber info retrieved from the phone.
+///
+namespace GsmComm.GsmCommunication
+{
+ public class SubscriberInfo
+ {
+ private string alpha;
+
+ private string number;
+
+ private int type;
+
+ private int speed;
+
+ private int service;
+
+ private int itc;
+
+ ///
+ /// Gets an optional alphanumeric string associated with ;
+ /// used character set is the one selected with .
+ ///
+ /// If the string is not defined, it is empty.
+ public string Alpha
+ {
+ get
+ {
+ return this.alpha;
+ }
+ }
+
+ ///
+ /// Gets a value for the information transfer capability.
+ ///
+ /// Valid values are zero or greater, -1 means this info is not available.
+ public int Itc
+ {
+ get
+ {
+ return this.itc;
+ }
+ }
+
+ ///
+ /// Gets the phone number of format specified by .
+ ///
+ public string Number
+ {
+ get
+ {
+ return this.number;
+ }
+ }
+
+ ///
+ /// Gets the service related to the phone number.
+ ///
+ /// Valid values are zero or greater, -1 means this info is not available.
+ /// Some defined values can be found in the enumeration.
+ ///
+ public int Service
+ {
+ get
+ {
+ return this.service;
+ }
+ }
+
+ ///
+ /// Gets a value for the speed for data calls.
+ ///
+ /// Valid values are zero or greater, -1 means this info is not available.
+ public int Speed
+ {
+ get
+ {
+ return this.speed;
+ }
+ }
+
+ ///
+ /// Gets the type of Address in integer format.
+ ///
+ public int Type
+ {
+ get
+ {
+ return this.type;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Phone number of format specified by type.
+ /// Type of address in integer format.
+ public SubscriberInfo(string number, int type)
+ {
+ this.alpha = string.Empty;
+ this.number = number;
+ this.type = type;
+ this.speed = -1;
+ this.service = -1;
+ this.itc = -1;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// An optional alphanumeric string associated with number
+ /// Phone number of format specified by type
+ /// Type of address in integer format
+ /// A value for the speed of data calls
+ /// The service related to the phone number
+ /// A value for the information transfer capability
+ ///
+ /// Valid values for speed, service and itc are zero or greater,
+ /// set values to -1 where the information is not available.
+ ///
+ public SubscriberInfo(string alpha, string number, int type, int speed, int service, int itc)
+ {
+ this.alpha = alpha;
+ this.number = number;
+ this.type = type;
+ this.speed = speed;
+ this.service = service;
+ this.itc = itc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GSMCommunication/Properties/AssemblyInfo.cs b/GSMCommunication/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..1986f90
--- /dev/null
+++ b/GSMCommunication/Properties/AssemblyInfo.cs
@@ -0,0 +1,17 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyCompany("Stefan Mayr")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCopyright("Copyright © 2004-2011 Stefan Mayr")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyFileVersion("1.21.0.0")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyTitle("GSM Communication")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyVersion("1.21.0.0")]
+[assembly: CompilationRelaxations(8)]
+[assembly: ComVisible(false)]
+[assembly: Guid("eec0C65f-a333-42d5-82b9-163a57814507")]
+[assembly: RuntimeCompatibility(WrapNonExceptionThrows=true)]
diff --git a/PDUConverter/GsmComm.PduConverter/AddressType.cs b/PDUConverter/GsmComm.PduConverter/AddressType.cs
new file mode 100644
index 0000000..1a8067c
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/AddressType.cs
@@ -0,0 +1,155 @@
+using System;
+
+///
+/// Indicates the format of a phone number.
+///
+///
+/// The most common value of this octet is 91 hex (10010001 bin), which indicates international format.
+/// A phone number in international format looks like 46708251358 (where the country code is 46).
+/// In the national (or unknown) format the same phone number would look like 0708251358. The international
+/// format is the most generic, and it has to be accepted also when the message is destined to a recipient
+/// in the same country as the MSC or as the SGSN.
+///
+namespace GsmComm.PduConverter
+{
+ public class AddressType
+ {
+ ///
+ /// Unknown type of number and numbering plan.
+ ///
+ public const byte Unknown = 0;
+
+ ///
+ /// Unknown type of number, telephone numbering plan.
+ ///
+ public const byte UnknownPhone = 129;
+
+ ///
+ /// International number, telephone numbering plan.
+ ///
+ public const byte InternationalPhone = 145;
+
+ private bool bit7;
+
+ private byte ton;
+
+ private byte npi;
+
+ ///
+ /// The Numbering Plan Identification.
+ ///
+ ///
+ /// The Numbering-plan-identification applies for Type-of-number = 000, 001 and 010.
+ /// For Type-of-number = 101 bits 3,2,1,0 are reserved and shall be transmitted as 0000.
+ /// Note that for addressing any of the entities SC, MSC, SGSN or MS, Numbering-plan-identification = 0001
+ /// will always be used. However, for addressing the SME, any specified Numbering-plan-identification
+ /// value may be used.
+ ///
+ public byte Npi
+ {
+ get
+ {
+ return this.npi;
+ }
+ set
+ {
+ this.npi = value;
+ }
+ }
+
+ ///
+ /// The Type of number.
+ ///
+ public byte Ton
+ {
+ get
+ {
+ return this.ton;
+ }
+ set
+ {
+ this.ton = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public AddressType()
+ {
+ this.bit7 = true;
+ this.ton = 0;
+ this.npi = 0;
+ }
+
+ ///
+ /// Initializes a new instance of the class using the given value.
+ ///
+ /// The Type-of-Address octet to initialize the object with.
+ public AddressType(byte toa)
+ {
+ this.bit7 = (toa & 128) > 0;
+ this.ton = (byte)(toa >> 4 & 7);
+ this.npi = (byte)(toa & 15);
+ }
+
+ public static implicit operator AddressType(byte toa)
+ {
+ return new AddressType(toa);
+ }
+
+ public static implicit operator Byte(AddressType a)
+ {
+ return a.ToByte();
+ }
+
+ ///
+ /// Returns the byte equivalent of this instance.
+ ///
+ /// The byte value.
+ public byte ToByte()
+ {
+ int num;
+ if (this.bit7)
+ {
+ num = 128;
+ }
+ else
+ {
+ num = 0;
+ }
+ byte num1 = (byte)(num | this.ton << 4 | this.npi);
+ return num1;
+ }
+
+ ///
+ /// Indicates the Numbering Plan Identification (NPI) of the phone number.
+ ///
+ public enum NumberingPlan : byte
+ {
+ Unknown,
+ Telephone,
+ Data,
+ Telex,
+ National,
+ Private,
+ Ermes,
+ Reserved
+ }
+
+ ///
+ /// Indicates the type of the phone number (TON).
+ ///
+ public enum TypeOfNumber : byte
+ {
+ Unknown,
+ International,
+ National,
+ NetworkSpecific,
+ Subscriber,
+ Alphanumeric,
+ Abbreviated,
+ Reserved
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/BcdWorker.cs b/PDUConverter/GsmComm.PduConverter/BcdWorker.cs
new file mode 100644
index 0000000..7c62d56
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/BcdWorker.cs
@@ -0,0 +1,151 @@
+using System;
+
+///
+/// A class for working with BCD encoded data strings.
+///
+namespace GsmComm.PduConverter
+{
+ public class BcdWorker
+ {
+ public BcdWorker()
+ {
+ }
+
+ ///
+ /// Counts the number of bytes in a BCD encoded string.
+ ///
+ /// The string containing the BCD data.
+ /// The byte count.
+ public static int CountBytes(string s)
+ {
+ return s.Length / 2;
+ }
+
+ ///
+ /// Swaps the semi-octets of a BCD encoded string and checks the length.
+ ///
+ /// The string to decode. Must be of even length.
+ /// The converted value.
+ /// String length is not even.
+ /// 21436587 becomes 12345678.
+ public static string DecodeSemiOctets(string data)
+ {
+ if (data.Length % 2 == 0)
+ {
+ string empty = string.Empty;
+ for (int i = 0; i < data.Length; i = i + 2)
+ {
+ empty = string.Concat(empty, data.Substring(i + 1, 1), data.Substring(i, 1));
+ }
+ return empty;
+ }
+ else
+ {
+ throw new ArgumentException("String length must be even.");
+ }
+ }
+
+ ///
+ /// Swaps the semi-octets of a BCD encoded string.
+ ///
+ /// The string to convert.
+ ///
+ /// If the string is not of even length, it is padded with a
+ /// hexadecimal "F" before converting.
+ /// This method does not verify the actual contents of the string.
+ ///
+ /// The converted value.
+ ///
+ /// A string containing "12345678" will become "21436587".
+ /// A string containing "1234567" will become "214365F7".
+ ///
+ public static string EncodeSemiOctets(string data)
+ {
+ if (data.Length % 2 != 0)
+ {
+ data = string.Concat(data, "F");
+ }
+ string empty = string.Empty;
+ for (int i = 0; i < data.Length; i = i + 2)
+ {
+ empty = string.Concat(empty, data.Substring(i + 1, 1), data.Substring(i, 1));
+ }
+ return empty;
+ }
+
+ ///
+ /// Swaps the semi-octets of a BCD encoded string.
+ ///
+ /// The string to convert.
+ /// The width to pad the string to before converting.
+ /// Padding character is hexadecimal "F".
+ ///
+ /// This method does not verify the actual contents of the string.
+ ///
+ /// The converted value.
+ /// totalWidth is not even.
+ public static string EncodeSemiOctets(string data, int totalWidth)
+ {
+ if (totalWidth % 2 == 0)
+ {
+ return BcdWorker.EncodeSemiOctets(data.PadRight(totalWidth, 'F'));
+ }
+ else
+ {
+ throw new ArgumentException("totalWidth must be even.", "totalWidth");
+ }
+ }
+
+ ///
+ /// Gets a single byte out of a BCD encoded string.
+ ///
+ /// The string containing the BCD data.
+ /// The position in the string to start.
+ /// The byte at the specified position.
+ /// No range checking is performed.
+ public static byte GetByte(string s, int index)
+ {
+ string str = s.Substring(index * 2, 2);
+ return Calc.HexToInt(str)[0];
+ }
+
+ ///
+ /// Gets multiple bytes out of a BCD encoded string.
+ ///
+ /// The string containing the BCD data.
+ /// The position in the string to start.
+ /// The number of bytes to read.
+ /// The bytes within the specified range.
+ /// No range checking is performed.
+ public static byte[] GetBytes(string s, int index, int length)
+ {
+ string str = s.Substring(index * 2, length * 2);
+ return Calc.HexToInt(str);
+ }
+
+ ///
+ /// Gets multiple bytes as string out of a BCD encoded string.
+ ///
+ /// The string containing the BCD data.
+ /// The position in the string to start.
+ /// The number of bytes to read.
+ /// The bytes within the specified range.
+ /// No range checking is performed.
+ public static string GetBytesString(string s, int index, int length)
+ {
+ return s.Substring(index * 2, length * 2);
+ }
+
+ ///
+ /// Gets a single byte as string out of a BCD encoded string.
+ ///
+ /// The string containing the BCD data.
+ /// The byte at the specified position.
+ /// The byte at the specified position.
+ /// No range checking is performed.
+ public static string GetByteString(string s, int index)
+ {
+ return s.Substring(index * 2, 2);
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/Calc.cs b/PDUConverter/GsmComm.PduConverter/Calc.cs
new file mode 100644
index 0000000..53e5994
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/Calc.cs
@@ -0,0 +1,173 @@
+using System;
+
+///
+/// Performs various numerical conversions and calculations.
+///
+namespace GsmComm.PduConverter
+{
+ public class Calc
+ {
+ private static char[] hexDigits;
+
+ static Calc()
+ {
+ char[] chrArray = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ Calc.hexDigits = chrArray;
+ }
+
+ public Calc()
+ {
+ }
+
+ ///
+ /// Converts a bit string into a byte.
+ ///
+ /// The string to convert.
+ /// The converted value.
+ public static byte BinToInt(string s)
+ {
+ return Convert.ToByte(s, 2);
+ }
+
+ ///
+ /// Converts a BCD encoded string (hexadecimal) into its byte representation.
+ ///
+ /// The string to convert.
+ ///
+ /// The length of the string should be even. This is not checked
+ /// here to be able to process truncated strings.
+ ///
+ /// The converted value.
+ ///
+ /// A string containing "41" will become {0x41}, which equals
+ /// the character 'A'.
+ /// A string containing "414242" will become {0x41, 0x42, 0x43}
+ /// which equals the string "ABC".
+ ///
+ public static byte[] HexToInt(string s)
+ {
+ byte[] num = new byte[s.Length / 2];
+ for (int i = 0; i < s.Length / 2; i++)
+ {
+ string str = s.Substring(i * 2, 2);
+ num[i] = Convert.ToByte(str, 16);
+ }
+ return num;
+ }
+
+ ///
+ /// Converts a byte into a bit string.
+ ///
+ /// The byte to convert.
+ ///
+ /// The final length the string should have. If the resulting string is
+ /// shorter than this value, it is padded with leading zeroes.
+ ///
+ /// The converted value.
+ public static string IntToBin(byte b, byte size)
+ {
+ return Convert.ToString(b, 2).PadLeft(size, '0');
+ }
+
+ ///
+ /// Converts a byte array into its hexadecimal representation (BCD encoding).
+ ///
+ /// The byte array to convert.
+ /// The converted value.
+ public static string IntToHex(byte[] bytes)
+ {
+ char[] chrArray = new char[(int)bytes.Length * 2];
+ for (int i = 0; i < (int)bytes.Length; i++)
+ {
+ int num = bytes[i];
+ chrArray[i * 2] = Calc.hexDigits[num >> 4];
+ chrArray[i * 2 + 1] = Calc.hexDigits[num & 15];
+ }
+ return new string(chrArray);
+ }
+
+ ///
+ /// Converts a byte array into its hexadecimal representation (BCD encoding).
+ ///
+ /// The byte array to convert.
+ /// The starting index of the byte array to convert.
+ /// The number of bytes to convert.
+ /// The converted value.
+ public static string IntToHex(byte[] bytes, int index, int count)
+ {
+ char[] chrArray = new char[count * 2];
+ for (int i = 0; i < count; i++)
+ {
+ int num = bytes[index + i];
+ chrArray[i * 2] = Calc.hexDigits[num >> 4];
+ chrArray[i * 2 + 1] = Calc.hexDigits[num & 15];
+ }
+ return new string(chrArray);
+ }
+
+ ///
+ /// Converts a byte into its BCD (hexadecimal) representation.
+ ///
+ /// The byte to convert.
+ /// The converted value.
+ public static string IntToHex(byte b)
+ {
+ return string.Concat(Calc.hexDigits[b >> 4].ToString(), Calc.hexDigits[b & 15].ToString());
+ }
+
+ ///
+ /// Determines if a string is a hexadecimal character.
+ ///
+ /// The character to check.
+ /// true if the character is a hex char, false otherwise.
+ public static bool IsHexDigit(char c)
+ {
+ char upper = char.ToUpper(c);
+ char[] chrArray = Calc.hexDigits;
+ int num = 0;
+ while (num < (int)chrArray.Length)
+ {
+ char chr = chrArray[num];
+ if (upper != chr)
+ {
+ num++;
+ }
+ else
+ {
+ bool flag = true;
+ return flag;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Determines if a string consists only of hexadecimal characters.
+ ///
+ /// The string to check.
+ /// true if the string is a hex string, false otherwise.
+ public static bool IsHexString(string s)
+ {
+ if (s.Length != 0)
+ {
+ int num = 0;
+ while (num < s.Length)
+ {
+ if (Calc.IsHexDigit(s[num]))
+ {
+ num++;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/DataCodingScheme.cs b/PDUConverter/GsmComm.PduConverter/DataCodingScheme.cs
new file mode 100644
index 0000000..4ab29a8
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/DataCodingScheme.cs
@@ -0,0 +1,268 @@
+using System;
+
+///
+/// Indicates how the user data is encoded, this class represents the TP-DCS field.
+///
+///
+/// The TP-Data-Coding-Scheme field, defined in GSM 03.40, indicates the data coding scheme of the TP-UD field,
+/// and may indicate a message class. Any reserved codings shall be assumed to be the GSM default alphabet
+/// (the same as codepoint 00000000) by a receiving entity. The octet is used according to a coding group
+/// which is indicated in bits 7..4
+///
+namespace GsmComm.PduConverter
+{
+ public abstract class DataCodingScheme
+ {
+ private const byte classValid = 16;
+
+ ///
+ /// Specifies no message class and 7-bit default alphabet.
+ ///
+ public const byte NoClass_7Bit = 0;
+
+ ///
+ /// Specifies message class 0 (immediate display) and 7-bit default alphabet.
+ ///
+ public const byte Class0_7Bit = 16;
+
+ ///
+ /// Specifies message class 1 (ME specific) and 7-bit default alphabet.
+ ///
+ public const byte Class1_7Bit = 17;
+
+ ///
+ /// Specifies message class 2 (SIM specific) and 7-bit default alphabet.
+ ///
+ public const byte Class2_7Bit = 18;
+
+ ///
+ /// Specifies message class 3 (TE specific) and 7-bit default alphabet.
+ ///
+ public const byte Class3_7Bit = 19;
+
+ ///
+ /// Specifies no message class and 8-bit data.
+ ///
+ public const byte NoClass_8Bit = 4;
+
+ ///
+ /// Specifies message class 0 (immediate display) and 8-bit data.
+ ///
+ public const byte Class0_8Bit = 20;
+
+ ///
+ /// Specifies message class 1 (ME specific) and 8-bit data.
+ ///
+ public const byte Class1_8Bit = 21;
+
+ ///
+ /// Specifies message class 2 (SIM specific) and 8-bit data.
+ ///
+ public const byte Class2_8Bit = 22;
+
+ ///
+ /// Specifies message class 3 (TE specific) and 8-bit data.
+ ///
+ public const byte Class3_8Bit = 23;
+
+ ///
+ /// Specifies no message class and UCS2 (16-bit) alphabet.
+ ///
+ public const byte NoClass_16Bit = 8;
+
+ ///
+ /// Specifies message class 0 (immediate display) and UCS2 (16-bit) alphabet.
+ ///
+ public const byte Class0_16Bit = 24;
+
+ ///
+ /// Specifies message class 1 (ME specific) and UCS2 (16-bit) alphabet.
+ ///
+ public const byte Class1_16Bit = 25;
+
+ ///
+ /// Specifies message class 2 (SIM specific) and UCS2 (16-bit) alphabet.
+ ///
+ public const byte Class2_16Bit = 26;
+
+ ///
+ /// Specifies message class 3 (TE specific) and UCS2 (16-bit) alphabet.
+ ///
+ public const byte Class3_16Bit = 27;
+
+ /// Offset for bit 7 value.
+ protected const byte bit7offset = 128;
+
+ /// Offset for bit 6 value.
+ protected const byte bit6offset = 64;
+
+ /// Offset for bit 5 value.
+ protected const byte bit5offset = 32;
+
+ /// Offset for bit 4 value.
+ protected const byte bit4offset = 16;
+
+ /// Offset for bit 3 value.
+ protected const byte bit3offset = 8;
+
+ /// Offset for bit 2 value.
+ protected const byte bit2offset = 4;
+
+ /// Offset for bit 1 value.
+ protected const byte bit1offset = 2;
+
+ /// Offset for bit 0 value.
+ protected const byte bit0offset = 1;
+
+ private byte codingGroup;
+
+ ///
+ /// Gets the alphabet being used.
+ ///
+ public abstract byte Alphabet
+ {
+ get;
+ }
+
+ ///
+ /// Gets the coding group, that tells about the further contents of the data coding scheme.
+ ///
+ public byte CodingGroup
+ {
+ get
+ {
+ return this.codingGroup;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The DCS byte to decode.
+ protected DataCodingScheme(byte dcs)
+ {
+ this.codingGroup = (byte)(dcs >> 4 & 15);
+ }
+
+ ///
+ /// Decodes the given DCS byte.
+ ///
+ /// The DCS octet to decode.
+ /// An object of type or one of its derived classes.
+ public static DataCodingScheme Decode(byte dcs)
+ {
+ DataCodingScheme messageWaitingDiscard;
+ byte num = (byte)(dcs >> 4 & 15);
+ if ((dcs & 64) != 0 || (dcs & 128) != 0)
+ {
+ byte num1 = num;
+ switch (num1)
+ {
+ case 12:
+ {
+ messageWaitingDiscard = new MessageWaitingDiscard(dcs);
+ break;
+ }
+ case 13:
+ {
+ messageWaitingDiscard = new MessageWaitingStore(dcs);
+ break;
+ }
+ case 14:
+ {
+ messageWaitingDiscard = new MessageWaitingStoreUcs2(dcs);
+ break;
+ }
+ case 15:
+ {
+ messageWaitingDiscard = new MessageCoding(dcs);
+ break;
+ }
+ default:
+ {
+ messageWaitingDiscard = new ReservedCodingGroup(dcs);
+ break;
+ }
+ }
+ }
+ else
+ {
+ messageWaitingDiscard = new GeneralDataCoding(dcs);
+ }
+ return messageWaitingDiscard;
+ }
+
+ ///
+ /// Lists the available alphabets within a general data coding indication DCS.
+ ///
+ public enum Alphabets : byte
+ {
+ DefaultAlphabet,
+ EightBit,
+ Ucs2,
+ Reserved
+ }
+
+ ///
+ /// Data coding/message class. Members can be combined.
+ ///
+ /// At least a "Group" member must be specified.
+ [Flags]
+ public enum DataCoding
+ {
+ Alpha7BitDefault = 0,
+ Class0 = 0,
+ Class1 = 1,
+ Class2 = 2,
+ Class3 = 3,
+ Alpha8Bit = 4,
+ Group_DataCoding = 240
+ }
+
+ ///
+ /// General data coding indication. Members can be combined.
+ ///
+ [Flags]
+ public enum GeneralCoding : byte
+ {
+ Uncompressed,
+ Alpha7BitDefault,
+ NoClass,
+ Alpha8Bit,
+ Alpha16Bit,
+ AlphaReserved,
+ Class0,
+ Class1,
+ Class2,
+ Class3,
+ Compressed
+ }
+
+ ///
+ /// Lists the available message codings within a data coding/message class DCS.
+ ///
+ public enum MessageCodings : byte
+ {
+ DefaultAlphabet,
+ EightBit
+ }
+
+ ///
+ /// Message waiting indication. Members can be combined.
+ ///
+ /// At least a "Group" member must be specified.
+ [Flags]
+ public enum MessageWaiting : byte
+ {
+ SetIndicationInactive,
+ VoicemailMsgWaiting,
+ FaxMsgWaiting,
+ EMailMsgWaiting,
+ OtherMsgWaiting,
+ SetIndicationActive,
+ Group_Discard_7BitDefault,
+ Group_Store_7BitDefault,
+ Group_Store_16Bit
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/GeneralDataCoding.cs b/PDUConverter/GsmComm.PduConverter/GeneralDataCoding.cs
new file mode 100644
index 0000000..aff04c9
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/GeneralDataCoding.cs
@@ -0,0 +1,75 @@
+using System;
+
+///
+/// General Data Coding indication
+///
+namespace GsmComm.PduConverter
+{
+ public class GeneralDataCoding : DataCodingScheme
+ {
+ private bool compressed;
+
+ private bool classSpecified;
+
+ private byte alphabet;
+
+ private byte messageClass;
+
+ ///
+ /// Gets the alphabet being used.
+ ///
+ public override byte Alphabet
+ {
+ get
+ {
+ return this.alphabet;
+ }
+ }
+
+ ///
+ /// Determines if the property has a message class meaning. If not,
+ /// the property contains a reserved value and has no message class meaning.
+ ///
+ public bool ClassSpecified
+ {
+ get
+ {
+ return this.classSpecified;
+ }
+ }
+
+ ///
+ /// Gets whether the text is compressed.
+ ///
+ public bool Compressed
+ {
+ get
+ {
+ return this.compressed;
+ }
+ }
+
+ ///
+ /// Gets the message class.
+ ///
+ public byte MessageClass
+ {
+ get
+ {
+ return this.messageClass;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The DCS byte to decode.
+ public GeneralDataCoding(byte dcs) : base(dcs)
+ {
+ this.compressed = (dcs & 32) > 0;
+ this.classSpecified = (dcs & 16) > 0;
+ this.alphabet = (byte)(dcs >> 2 & 3);
+ this.messageClass = (byte)(dcs & 3);
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/ITimestamp.cs b/PDUConverter/GsmComm.PduConverter/ITimestamp.cs
new file mode 100644
index 0000000..480c13c
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/ITimestamp.cs
@@ -0,0 +1,15 @@
+///
+/// Represents a common interface for messages to return their relevant
+/// timestamp.
+///
+namespace GsmComm.PduConverter
+{
+ public interface ITimestamp
+ {
+ ///
+ /// Returns the relevant timestamp.
+ ///
+ /// A structure representing the relevant message timestamp.
+ SmsTimestamp GetTimestamp();
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/IncomingMessageFlags.cs b/PDUConverter/GsmComm.PduConverter/IncomingMessageFlags.cs
new file mode 100644
index 0000000..f50cf76
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/IncomingMessageFlags.cs
@@ -0,0 +1,49 @@
+using System;
+
+///
+/// The base class for the message flags of incoming messages.
+///
+namespace GsmComm.PduConverter
+{
+ public abstract class IncomingMessageFlags
+ {
+ ///
+ /// Gets the message type.
+ ///
+ public abstract IncomingMessageType MessageType
+ {
+ get;
+ }
+
+ protected IncomingMessageFlags()
+ {
+ }
+
+ ///
+ /// In derived classes, converts the specified value into a new instance of the class.
+ ///
+ /// A value.
+ protected abstract void FromByte(byte b);
+
+ public static implicit operator Byte(IncomingMessageFlags flags)
+ {
+ return flags.ToByte();
+ }
+
+ ///
+ /// In derived classes, returns the byte equivalent of this instance.
+ ///
+ /// The byte value.
+ public abstract byte ToByte();
+
+ ///
+ /// Returns the string equivalent of this instance.
+ ///
+ /// The string.
+ public override string ToString()
+ {
+ byte num = this.ToByte();
+ return num.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/IncomingMessageType.cs b/PDUConverter/GsmComm.PduConverter/IncomingMessageType.cs
new file mode 100644
index 0000000..6d18471
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/IncomingMessageType.cs
@@ -0,0 +1,15 @@
+///
+/// Specifies the type of the incoming message.
+///
+namespace GsmComm.PduConverter
+{
+ public enum IncomingMessageType
+ {
+ /// Specifies that the message is an SMS-DELIVER.
+ SmsDeliver,
+ /// Specifies that the message is an SMS-STATUS-REPORT.
+ SmsStatusReport,
+ /// Specifies that the message is an SMS-SUBMIT-REPORT.
+ SmsSubmitReport
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/IncomingSmsPdu.cs b/PDUConverter/GsmComm.PduConverter/IncomingSmsPdu.cs
new file mode 100644
index 0000000..c341a8b
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/IncomingSmsPdu.cs
@@ -0,0 +1,131 @@
+using System;
+
+///
+/// Represents an incoming SMS PDU.
+///
+namespace GsmComm.PduConverter
+{
+ public abstract class IncomingSmsPdu : SmsPdu
+ {
+ private const byte TP_MTI_SMS_Deliver = 0;
+
+ private const byte TP_MTI_SMS_Submit_Report = 1;
+
+ private const byte TP_MTI_SMS_Status_Report = 2;
+
+ ///
+ /// The flags for this message.
+ ///
+ protected IncomingMessageFlags messageFlags;
+
+ ///
+ /// Gets the message type.
+ ///
+ public IncomingMessageType MessageType
+ {
+ get
+ {
+ return this.messageFlags.MessageType;
+ }
+ }
+
+ protected IncomingSmsPdu()
+ {
+ }
+
+ ///
+ /// Decodes an incoming SMS PDU stream.
+ ///
+ /// The PDU string to decode.
+ /// Specify true if the PDU data contains an SMSC header, otherwise false.
+ /// The size of the PDU data in bytes, not counting the SMSC header. Set to -1 if unknown.
+ /// An object representing the decoded message.
+ public static IncomingSmsPdu Decode(string pdu, bool includesSmscData, int actualLength)
+ {
+ if (pdu != string.Empty)
+ {
+ int num = 0;
+ if (includesSmscData)
+ {
+ int num1 = num;
+ num = num1 + 1;
+ byte num2 = BcdWorker.GetByte(pdu, num1);
+ if (num2 > 0)
+ {
+ num = num + num2;
+ }
+ }
+ int num3 = num;
+ IncomingMessageType messageType = IncomingSmsPdu.GetMessageType(BcdWorker.GetByte(pdu, num3));
+ IncomingMessageType incomingMessageType = messageType;
+ switch (incomingMessageType)
+ {
+ case IncomingMessageType.SmsDeliver:
+ {
+ return new SmsDeliverPdu(pdu, includesSmscData, actualLength);
+ }
+ case IncomingMessageType.SmsStatusReport:
+ {
+ return new SmsStatusReportPdu(pdu, includesSmscData, actualLength);
+ }
+ }
+ throw new NotSupportedException(string.Concat("Message type ", messageType.ToString(), " recognized, but not supported by the SMS decoder."));
+ }
+ else
+ {
+ throw new ArgumentException("pdu must not be an empty string.");
+ }
+ }
+
+ ///
+ /// Decodes an incoming SMS PDU stream.
+ ///
+ /// The PDU string to decode.
+ /// Specify true if the PDU data contains an SMSC header, otherwise false.
+ /// An object representing the decoded message.
+ /// Use this overload only if you do not know the size of the PDU data.
+ public static IncomingSmsPdu Decode(string pdu, bool includesSmscData)
+ {
+ return IncomingSmsPdu.Decode(pdu, includesSmscData, -1);
+ }
+
+ private static IncomingMessageType GetMessageType(byte flags)
+ {
+ IncomingMessageType incomingMessageType;
+ int num;
+ if ((flags & 2) > 0)
+ {
+ num = 1;
+ }
+ else
+ {
+ num = 0;
+ }
+ byte num1 = (byte)(num * 2 + (flags & 1));
+ byte num2 = num1;
+ if (num2 == 0)
+ {
+ incomingMessageType = IncomingMessageType.SmsDeliver;
+ }
+ else if (num2 == 1)
+ {
+ incomingMessageType = IncomingMessageType.SmsSubmitReport;
+ }
+ else if (num2 == 2)
+ {
+ incomingMessageType = IncomingMessageType.SmsStatusReport;
+ }
+ else
+ {
+ string[] str = new string[5];
+ str[0] = "Unknown message type ";
+ str[1] = num1.ToString();
+ str[2] = " (flags=";
+ str[3] = flags.ToString();
+ str[4] = ")";
+ throw new ArgumentException(string.Concat(str), "flags");
+ }
+ return incomingMessageType;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/KnownMessageStatus.cs b/PDUConverter/GsmComm.PduConverter/KnownMessageStatus.cs
new file mode 100644
index 0000000..23595eb
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/KnownMessageStatus.cs
@@ -0,0 +1,63 @@
+using System;
+
+///
+/// This enumarator represents the known status codes of a TP-ST octet.
+/// Reserved and SC specific values are not part of this list.
+///
+namespace GsmComm.PduConverter
+{
+ public enum KnownMessageStatus : byte
+ {
+ /// Short message received by the SME.
+ OK_Received,
+ /// Short message forwarded by the SC to the SME but the SC is unable to confirm delivery.
+ OK_NotConfirmed,
+ /// Short message replaced by the SC.
+ OK_Replaced,
+ /// Congestion.
+ Temp_Congestion,
+ /// SME busy.
+ Temp_SmeBusy,
+ /// No response from SME.
+ Temp_NoResponseFromSme,
+ /// Service Rejected.
+ Temp_ServiceRejected,
+ /// Quality of service not available.
+ Temp_QosNotAvailable,
+ /// Error in SME.
+ Temp_ErrorInSme,
+ /// Remote procedure error.
+ Perm_RemoteProcedureError,
+ /// Incompatible destination.
+ Perm_IncompatibleDestination,
+ /// Connection rejected by SME.
+ Perm_ConnectionRejectedBySme,
+ /// Not obtainable.
+ Perm_NotObtainable,
+ /// Quality of service not available.
+ Perm_QosNotAvailable,
+ /// No interworking available.
+ Perm_NoInterworkingAvailable,
+ /// SM Validity Period expired.
+ Perm_SMValidityPeriodExpired,
+ /// SM Deleted by originating SME.
+ Perm_SMDeletedByOriginatingSme,
+ /// SM Deleted by SC Administration.
+ Perm_SMDeletedBySCAdministration,
+ /// SM does not exist (The SM may have previously existed in the SC but the
+ /// SC no longer has knowledge of it or the SM may never have previously existed in the SC).
+ Perm_SMDoesNotExist,
+ /// Congestion.
+ Ntemp_Congestion,
+ /// SME busy.
+ Ntemp_SmeBusy,
+ /// No response from SME.
+ Ntemp_NoResponseFromSme,
+ /// Service rejected.
+ Ntemp_ServiceRejected,
+ /// Quality of service not available.
+ Ntemp_QosNotAvailable,
+ /// Error in SME.
+ Ntemp_ErrorInSme
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/MessageCoding.cs b/PDUConverter/GsmComm.PduConverter/MessageCoding.cs
new file mode 100644
index 0000000..39a4b7c
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/MessageCoding.cs
@@ -0,0 +1,70 @@
+using System;
+
+///
+/// Data coding/Message class
+///
+namespace GsmComm.PduConverter
+{
+ public class MessageCoding : DataCodingScheme
+ {
+ private bool bit3;
+
+ private byte dataCoding;
+
+ private byte messageClass;
+
+ ///
+ /// Gets the alphabet being used.
+ ///
+ public override byte Alphabet
+ {
+ get
+ {
+ return this.dataCoding;
+ }
+ }
+
+ ///
+ /// Gets the data coding.
+ ///
+ public byte DataCoding
+ {
+ get
+ {
+ return this.dataCoding;
+ }
+ }
+
+ ///
+ /// Gets the message class.
+ ///
+ public byte MessageClass
+ {
+ get
+ {
+ return this.messageClass;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The DCS byte to decode.
+ public MessageCoding(byte dcs) : base(dcs)
+ {
+ object obj;
+ this.bit3 = (dcs & 8) > 0;
+ MessageCoding messageCoding = this;
+ if ((dcs & 4) > 0)
+ {
+ obj = 1;
+ }
+ else
+ {
+ obj = null;
+ }
+ messageCoding.dataCoding = (byte)obj;
+ this.messageClass = (byte)(dcs & 3);
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/MessageStatus.cs b/PDUConverter/GsmComm.PduConverter/MessageStatus.cs
new file mode 100644
index 0000000..a83b6a7
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/MessageStatus.cs
@@ -0,0 +1,141 @@
+using System;
+
+///
+/// TP-ST / TP-Status.
+///
+namespace GsmComm.PduConverter
+{
+ public struct MessageStatus
+ {
+ private byte status;
+
+ ///
+ /// Gets the status category.
+ ///
+ ///
+ /// If the valus does not fall into one of the predefined categories,
+ /// is returned.
+ ///
+ public StatusCategory Category
+ {
+ get
+ {
+ if (this.status < 0 || this.status > 31)
+ {
+ if (this.status < 32 || this.status > 47)
+ {
+ if (this.status < 64 || this.status > 95)
+ {
+ if (this.status < 96 || this.status > 127)
+ {
+ return StatusCategory.Reserved;
+ }
+ else
+ {
+ return StatusCategory.TemporaryErrorNoRetry;
+ }
+ }
+ else
+ {
+ return StatusCategory.PermanentError;
+ }
+ }
+ else
+ {
+ return StatusCategory.TemporaryErrorWithRetry;
+ }
+ }
+ else
+ {
+ return StatusCategory.Success;
+ }
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The status code.
+ public MessageStatus(byte status)
+ {
+ this.status = status;
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// One of the values.
+ public MessageStatus(KnownMessageStatus status)
+ {
+ this.status = (byte)status;
+ }
+
+ ///
+ /// Retrieves the known status of the current message status.
+ ///
+ /// Ae representing the message status.
+ /// Check first with before calling this method.
+ /// Message status is not a known message status.
+ public KnownMessageStatus GetKnownStatus()
+ {
+ if (!this.IsKnownStatus())
+ {
+ throw new ArgumentException(string.Concat(this.status.ToString(), " is not a known message status."));
+ }
+ else
+ {
+ return (KnownMessageStatus)Enum.Parse(typeof(KnownMessageStatus), this.status.ToString());
+ }
+ }
+
+ ///
+ /// Checks if the message status exists within the known status list.
+ ///
+ /// true if the status is a known status, otherwise false.
+ public bool IsKnownStatus()
+ {
+ return Enum.IsDefined(typeof(KnownMessageStatus), this.status);
+ }
+
+ public static implicit operator Byte(MessageStatus s)
+ {
+ return s.ToByte();
+ }
+
+ public static implicit operator MessageStatus(byte b)
+ {
+ return new MessageStatus(b);
+ }
+
+ public static implicit operator MessageStatus(KnownMessageStatus s)
+ {
+ return new MessageStatus(s);
+ }
+
+ ///
+ /// Returns the byte representation of the status.
+ ///
+ /// A value representing the object's value.
+ public byte ToByte()
+ {
+ return this.status;
+ }
+
+ ///
+ /// Returns the string representation of the status.
+ ///
+ /// The string representation of the known status if it is a known status,
+ /// the numerical status value otherwise.
+ public override string ToString()
+ {
+ if (!this.IsKnownStatus())
+ {
+ return this.status.ToString();
+ }
+ else
+ {
+ return this.GetKnownStatus().ToString();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/MessageWaitingDiscard.cs b/PDUConverter/GsmComm.PduConverter/MessageWaitingDiscard.cs
new file mode 100644
index 0000000..8281c2a
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/MessageWaitingDiscard.cs
@@ -0,0 +1,29 @@
+using System;
+
+///
+/// Message Waiting Indication Group: Discard Message
+///
+namespace GsmComm.PduConverter
+{
+ public class MessageWaitingDiscard : MessageWaitingIndication
+ {
+ ///
+ /// Gets the alphabet being used.
+ ///
+ public override byte Alphabet
+ {
+ get
+ {
+ return 0;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The DCS byte to decode.
+ public MessageWaitingDiscard(byte dcs) : base(dcs)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/MessageWaitingIndication.cs b/PDUConverter/GsmComm.PduConverter/MessageWaitingIndication.cs
new file mode 100644
index 0000000..30cef91
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/MessageWaitingIndication.cs
@@ -0,0 +1,50 @@
+using System;
+
+///
+/// Message waiting indication. This class is abstract.
+///
+namespace GsmComm.PduConverter
+{
+ public abstract class MessageWaitingIndication : DataCodingScheme
+ {
+ private bool indicationActive;
+
+ private bool bit2;
+
+ private byte indicationType;
+
+ ///
+ /// Gets if the indication should be set active.
+ ///
+ /// If true, the indication should be set active, if false, the indication should be set inactive.
+ public bool IndicationActive
+ {
+ get
+ {
+ return this.indicationActive;
+ }
+ }
+
+ ///
+ /// Gets the indication type, how the indication should be shown.
+ ///
+ public byte IndicationType
+ {
+ get
+ {
+ return this.indicationType;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The DCS byte to decode.
+ public MessageWaitingIndication(byte dcs) : base(dcs)
+ {
+ this.indicationType = (byte)(dcs & 3);
+ this.bit2 = (dcs & 4) > 0;
+ this.indicationActive = (dcs & 8) > 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/MessageWaitingStore.cs b/PDUConverter/GsmComm.PduConverter/MessageWaitingStore.cs
new file mode 100644
index 0000000..5d372ec
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/MessageWaitingStore.cs
@@ -0,0 +1,29 @@
+using System;
+
+///
+/// Message Waiting Indication Group: Store Message
+///
+namespace GsmComm.PduConverter
+{
+ public class MessageWaitingStore : MessageWaitingIndication
+ {
+ ///
+ /// Gets the alphabet being used.
+ ///
+ public override byte Alphabet
+ {
+ get
+ {
+ return 0;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The DCS byte to decode.
+ public MessageWaitingStore(byte dcs) : base(dcs)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/MessageWaitingStoreUcs2.cs b/PDUConverter/GsmComm.PduConverter/MessageWaitingStoreUcs2.cs
new file mode 100644
index 0000000..7494a86
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/MessageWaitingStoreUcs2.cs
@@ -0,0 +1,29 @@
+using System;
+
+///
+/// Message Waiting Indication Group: Store Message (UCS2)
+///
+namespace GsmComm.PduConverter
+{
+ public class MessageWaitingStoreUcs2 : MessageWaitingIndication
+ {
+ ///
+ /// Gets the alphabet being used.
+ ///
+ public override byte Alphabet
+ {
+ get
+ {
+ return 2;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The DCS byte to decode.
+ public MessageWaitingStoreUcs2(byte dcs) : base(dcs)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/OutgoingMessageFlags.cs b/PDUConverter/GsmComm.PduConverter/OutgoingMessageFlags.cs
new file mode 100644
index 0000000..2017877
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/OutgoingMessageFlags.cs
@@ -0,0 +1,49 @@
+using System;
+
+///
+/// The base class for the message flags of outgoing messages.
+///
+namespace GsmComm.PduConverter
+{
+ public abstract class OutgoingMessageFlags
+ {
+ ///
+ /// Gets the message type.
+ ///
+ public abstract OutgoingMessageType MessageType
+ {
+ get;
+ }
+
+ protected OutgoingMessageFlags()
+ {
+ }
+
+ ///
+ /// In derived classes, converts the specified value into a new instance of the class.
+ ///
+ /// A value.
+ protected abstract void FromByte(byte b);
+
+ public static implicit operator Byte(OutgoingMessageFlags flags)
+ {
+ return flags.ToByte();
+ }
+
+ ///
+ /// In derived classes, returns the byte equivalent of this instance.
+ ///
+ /// The byte value.
+ public abstract byte ToByte();
+
+ ///
+ /// Returns the string equivalent of this instance.
+ ///
+ /// The string.
+ public override string ToString()
+ {
+ byte num = this.ToByte();
+ return num.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/OutgoingMessageType.cs b/PDUConverter/GsmComm.PduConverter/OutgoingMessageType.cs
new file mode 100644
index 0000000..7ab3bc0
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/OutgoingMessageType.cs
@@ -0,0 +1,15 @@
+///
+/// Specifies the type of the outgoing message.
+///
+namespace GsmComm.PduConverter
+{
+ public enum OutgoingMessageType
+ {
+ /// Specifies that the message is an SMS-SUBMIT.
+ SmsSubmit,
+ /// Specifies that the message is an SMS-COMMAND.
+ SmsCommand,
+ /// Specifies that the message is an SMS-DELIVER-REPORT.
+ SmsDeliverReport
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/OutgoingSmsPdu.cs b/PDUConverter/GsmComm.PduConverter/OutgoingSmsPdu.cs
new file mode 100644
index 0000000..a268141
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/OutgoingSmsPdu.cs
@@ -0,0 +1,155 @@
+using System;
+
+///
+/// Represents an outgoing SMS PDU.
+///
+namespace GsmComm.PduConverter
+{
+ public abstract class OutgoingSmsPdu : SmsPdu
+ {
+ private const byte TP_MTI_SMS_Deliver_Report = 0;
+
+ private const byte TP_MTI_SMS_Submit = 1;
+
+ private const byte TP_MTI_SMS_Command = 2;
+
+ ///
+ /// The flags for this message.
+ ///
+ protected OutgoingMessageFlags messageFlags;
+
+ ///
+ /// The message reference.
+ ///
+ protected byte messageReference;
+
+ ///
+ /// Gets or sets the message reference.
+ ///
+ /// Represents the TP-Message-Reference octet of the PDU.
+ /// Normally there is no need to change this property because
+ /// the reference is set by the sending device..
+ ///
+ public byte MessageReference
+ {
+ get
+ {
+ return this.messageReference;
+ }
+ set
+ {
+ this.messageReference = value;
+ }
+ }
+
+ ///
+ /// Gets the message type.
+ ///
+ public OutgoingMessageType MessageType
+ {
+ get
+ {
+ return this.messageFlags.MessageType;
+ }
+ }
+
+ ///
+ /// Initializes a new instance.
+ ///
+ protected OutgoingSmsPdu()
+ {
+ this.messageReference = 0;
+ }
+
+ ///
+ /// Decodes an outgoing SMS PDU stream.
+ ///
+ /// The PDU string to decode
+ /// Specify true if the PDU data contains an SMSC header, otherwise false.
+ /// The length of the PDU in bytes, not including the SMSC header.
+ /// An object representing the decoded message.
+ public static OutgoingSmsPdu Decode(string pdu, bool includesSmscData, int actualLength)
+ {
+ if (pdu != string.Empty)
+ {
+ int num = 0;
+ if (includesSmscData)
+ {
+ int num1 = num;
+ num = num1 + 1;
+ byte num2 = BcdWorker.GetByte(pdu, num1);
+ if (num2 > 0)
+ {
+ num = num + num2;
+ }
+ }
+ int num3 = num;
+ OutgoingMessageType messageType = OutgoingSmsPdu.GetMessageType(BcdWorker.GetByte(pdu, num3));
+ OutgoingMessageType outgoingMessageType = messageType;
+ if (outgoingMessageType != OutgoingMessageType.SmsSubmit)
+ {
+ throw new NotSupportedException(string.Concat("Message type ", messageType.ToString(), " recognized, but not supported by the SMS decoder."));
+ }
+ else
+ {
+ return new SmsSubmitPdu(pdu, includesSmscData, actualLength);
+ }
+ }
+ else
+ {
+ throw new ArgumentException("pdu must not be an empty string.");
+ }
+ }
+
+ ///
+ /// Decodes an outgoing SMS PDU stream.
+ ///
+ /// The PDU string to decode.
+ /// Specify true if the PDU data contains an SMSC header, otherwise false.
+ /// An object representing the decoded message.
+ /// Use this method when the actual length of the message is not known.
+ public static OutgoingSmsPdu Decode(string pdu, bool includesSmscData)
+ {
+ return OutgoingSmsPdu.Decode(pdu, includesSmscData, -1);
+ }
+
+ private static OutgoingMessageType GetMessageType(byte flags)
+ {
+ OutgoingMessageType outgoingMessageType;
+ int num;
+ if ((flags & 2) > 0)
+ {
+ num = 1;
+ }
+ else
+ {
+ num = 0;
+ }
+ byte num1 = (byte)(num * 2 + (flags & 1));
+ byte num2 = num1;
+ if (num2 == 0)
+ {
+ outgoingMessageType = OutgoingMessageType.SmsDeliverReport;
+ }
+ else if (num2 == 1)
+ {
+ outgoingMessageType = OutgoingMessageType.SmsSubmit;
+ }
+ else if (num2 == 2)
+ {
+ outgoingMessageType = OutgoingMessageType.SmsCommand;
+ }
+ else
+ {
+ string[] str = new string[5];
+ str[0] = "Unknown message type ";
+ str[1] = num1.ToString();
+ str[2] = " (flags=";
+ str[3] = flags.ToString();
+ str[4] = ")";
+ throw new ArgumentException(string.Concat(str), "flags");
+ }
+ return outgoingMessageType;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/ParameterIndicator.cs b/PDUConverter/GsmComm.PduConverter/ParameterIndicator.cs
new file mode 100644
index 0000000..e98f069
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/ParameterIndicator.cs
@@ -0,0 +1,235 @@
+using System;
+
+///
+/// TP-PI / TP-Parameter-Indicator. Represents particular optional parameter
+/// presence in the fields which follow.
+///
+namespace GsmComm.PduConverter
+{
+ public class ParameterIndicator
+ {
+ private const byte bit0 = 1;
+
+ private const byte bit1 = 2;
+
+ private const byte bit2 = 4;
+
+ private const byte bit3 = 8;
+
+ private const byte bit4 = 16;
+
+ private const byte bit5 = 32;
+
+ private const byte bit6 = 64;
+
+ private const byte bit7 = 128;
+
+ private bool tp_pid;
+
+ private bool tp_dcs;
+
+ private bool tp_udl;
+
+ private bool reserved_bit3;
+
+ private bool reserved_bit4;
+
+ private bool reserved_bit5;
+
+ private bool reserved_bit6;
+
+ private bool extension;
+
+ ///
+ /// When set to true, will indicate that another TP-PI octet follows immediately afterwards.
+ ///
+ public bool Extension
+ {
+ get
+ {
+ return this.extension;
+ }
+ set
+ {
+ this.extension = value;
+ }
+ }
+
+ ///
+ /// Reserved. If set to true, the receiving entity should ignore
+ /// this setting.
+ ///
+ public bool Reserved_Bit3
+ {
+ get
+ {
+ return this.reserved_bit3;
+ }
+ set
+ {
+ this.reserved_bit3 = value;
+ }
+ }
+
+ ///
+ /// Reserved. If set to true, the receiving entity should ignore
+ /// this setting.
+ ///
+ public bool Reserved_Bit4
+ {
+ get
+ {
+ return this.reserved_bit4;
+ }
+ set
+ {
+ this.reserved_bit4 = value;
+ }
+ }
+
+ ///
+ /// Reserved. If set to true, the receiving entity should ignore
+ /// this setting.
+ ///
+ public bool Reserved_Bit5
+ {
+ get
+ {
+ return this.reserved_bit5;
+ }
+ set
+ {
+ this.reserved_bit5 = value;
+ }
+ }
+
+ ///
+ /// Reserved. If set to true, the receiving entity should ignore
+ /// this setting.
+ ///
+ public bool Reserved_Bit6
+ {
+ get
+ {
+ return this.reserved_bit6;
+ }
+ set
+ {
+ this.reserved_bit6 = value;
+ }
+ }
+
+ ///
+ /// When true, a TP-DCS field is present.
+ ///
+ public bool TP_DCS
+ {
+ get
+ {
+ return this.tp_dcs;
+ }
+ set
+ {
+ this.tp_dcs = value;
+ }
+ }
+
+ ///
+ /// When true, a TP-PID field is present.
+ ///
+ public bool TP_PID
+ {
+ get
+ {
+ return this.tp_pid;
+ }
+ set
+ {
+ this.tp_pid = value;
+ }
+ }
+
+ ///
+ /// When false, neither TP-UDL nor TP-UD field can be present.
+ ///
+ public bool TP_UDL
+ {
+ get
+ {
+ return this.tp_udl;
+ }
+ set
+ {
+ this.tp_udl = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The value to initialize the object with.
+ public ParameterIndicator(byte value)
+ {
+ this.tp_pid = (value & 1) > 0;
+ this.tp_dcs = (value & 2) > 0;
+ this.tp_udl = (value & 4) > 0;
+ this.reserved_bit3 = (value & 8) > 0;
+ this.reserved_bit4 = (value & 16) > 0;
+ this.reserved_bit5 = (value & 32) > 0;
+ this.reserved_bit6 = (value & 64) > 0;
+ this.extension = (value & 128) > 0;
+ }
+
+ public static implicit operator Byte(ParameterIndicator pi)
+ {
+ return pi.ToByte();
+ }
+
+ public static implicit operator ParameterIndicator(byte b)
+ {
+ return new ParameterIndicator(b);
+ }
+
+ ///
+ /// Returns the byte equivalent of this instance.
+ ///
+ /// The byte value.
+ public byte ToByte()
+ {
+ byte num = 0;
+ if (this.tp_pid)
+ {
+ num = (byte)(num | 1);
+ }
+ if (this.tp_dcs)
+ {
+ num = (byte)(num | 2);
+ }
+ if (this.tp_udl)
+ {
+ num = (byte)(num | 4);
+ }
+ if (this.reserved_bit3)
+ {
+ num = (byte)(num | 8);
+ }
+ if (this.reserved_bit4)
+ {
+ num = (byte)(num | 16);
+ }
+ if (this.reserved_bit5)
+ {
+ num = (byte)(num | 32);
+ }
+ if (this.reserved_bit6)
+ {
+ num = (byte)(num | 64);
+ }
+ if (this.extension)
+ {
+ num = (byte)(num | 128);
+ }
+ return num;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/PduParts.cs b/PDUConverter/GsmComm.PduConverter/PduParts.cs
new file mode 100644
index 0000000..fdea4d0
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/PduParts.cs
@@ -0,0 +1,264 @@
+using System;
+using System.Text;
+
+///
+/// Implements decoding routines for SMS PDU parts that are not implemented as separate objects.
+///
+namespace GsmComm.PduConverter
+{
+ public static class PduParts
+ {
+ ///
+ /// Decodes the text from 7-Bit user data.
+ ///
+ /// The user data to decode. Must contain an encoded GSM 7-Bit default text packed into octets.
+ /// The decoded user data.
+ public static string Decode7BitText(byte[] userData)
+ {
+ string septetsStr = TextDataConverter.OctetsToSeptetsStr(userData);
+ return TextDataConverter.SevenBitToString(septetsStr, true);
+ }
+
+ ///
+ /// Decodes an address out of a PDU string.
+ ///
+ /// The PDU string to use.
+ /// The index where to start in the string.
+ /// The address (phone number) read.
+ /// The address type of the read address.
+ public static void DecodeGeneralAddress(string pdu, ref int index, out string address, out byte addressType)
+ {
+ int num;
+ int num1 = index;
+ int num2 = num1;
+ index = num1 + 1;
+ byte num3 = BcdWorker.GetByte(pdu, num2);
+ int num4 = index;
+ int num5 = num4;
+ index = num4 + 1;
+ addressType = BcdWorker.GetByte(pdu, num5);
+ if (num3 <= 0)
+ {
+ address = string.Empty;
+ return;
+ }
+ else
+ {
+ bool flag = false;
+ if (num3 % 2 != 0)
+ {
+ num = num3 + 1;
+ }
+ else
+ {
+ num = (int)num3;
+ }
+ int length = num / 2;
+ if (index * 2 + length * 2 > pdu.Length - length * 2)
+ {
+ length = (pdu.Length - index * 2) / 2;
+ flag = true;
+ }
+ AddressType addressType1 = new AddressType(addressType);
+ if (addressType1.Ton != 5)
+ {
+ string bytesString = BcdWorker.GetBytesString(pdu, index, length);
+ index = index + length;
+ if (flag)
+ {
+ address = BcdWorker.DecodeSemiOctets(bytesString).Substring(0, length * 2);
+ return;
+ }
+ else
+ {
+ address = BcdWorker.DecodeSemiOctets(bytesString).Substring(0, num3);
+ return;
+ }
+ }
+ else
+ {
+ byte[] bytes = BcdWorker.GetBytes(pdu, index, length);
+ index = index + length;
+ address = PduParts.Decode7BitText(bytes);
+ return;
+ }
+ }
+ }
+
+ ///
+ /// Decodes an SMSC address out of a PDU string.
+ ///
+ /// The PDU string to use.
+ /// The index where to start in the string.
+ /// The address (phone number) read.
+ /// The address type of the read address.
+ public static void DecodeSmscAddress(string pdu, ref int index, out string address, out byte addressType)
+ {
+ int num = index;
+ int num1 = num;
+ index = num + 1;
+ byte num2 = BcdWorker.GetByte(pdu, num1);
+ if (num2 <= 0)
+ {
+ addressType = 0;
+ address = string.Empty;
+ return;
+ }
+ else
+ {
+ int num3 = index;
+ int num4 = num3;
+ index = num3 + 1;
+ byte num5 = BcdWorker.GetByte(pdu, num4);
+ int num6 = num2 - 1;
+ string bytesString = BcdWorker.GetBytesString(pdu, index, num6);
+ index = index + num6;
+ string str = BcdWorker.DecodeSemiOctets(bytesString);
+ if (str.EndsWith("F") || str.EndsWith("f"))
+ {
+ str = str.Substring(0, str.Length - 1);
+ }
+ addressType = num5;
+ address = str;
+ return;
+ }
+ }
+
+ ///
+ /// Decodes text from user data in the specified data coding scheme.
+ ///
+ /// The user data to decode. Must contain text according to the specified data coding scheme.
+ /// The data coding scheme specified in the PDU.
+ /// The decoded user data.
+ public static string DecodeText(byte[] userData, byte dataCodingScheme)
+ {
+ string str;
+ byte alphabet = DataCodingScheme.Decode(dataCodingScheme).Alphabet;
+ byte num = alphabet;
+ switch (num)
+ {
+ case 0:
+ {
+ str = PduParts.Decode7BitText(userData);
+ break;
+ }
+ case 1:
+ {
+ Label0:
+ str = PduParts.Decode7BitText(userData);
+ break;
+ }
+ case 2:
+ {
+ str = PduParts.DecodeUcs2Text(userData);
+ break;
+ }
+ default:
+ {
+ goto Label0;
+ }
+ }
+ return str;
+ }
+
+ ///
+ /// Decodes the text from UCS2 (16-Bit) user data.
+ ///
+ /// The user data to decode. Must contain an encoded UCS2 text.
+ /// The decoded user data.
+ public static string DecodeUcs2Text(byte[] userData)
+ {
+ Encoding bigEndianUnicode = Encoding.BigEndianUnicode;
+ return bigEndianUnicode.GetString(userData);
+ }
+
+ ///
+ /// Gets the user data out of the string.
+ ///
+ /// The PDU string to use.
+ /// The index where to start in the string.
+ /// The coding that was used to encode the data. Required to determine the proper data length.
+ /// Receives the user data length in bytes.
+ /// Received the user data.
+ ///
+ /// If there's no data, userDataLength will be set to 0 and userData to null.
+ /// The decoded data might require further processing, for example 7-bit data (septets) packed
+ /// into octets, that must be converted back to septets before the data can be used.
+ /// Processing will stop at the first character that is not hex encountered or if the
+ /// string ends too early. It will not change the userDataLength read from the string.
+ ///
+ public static void DecodeUserData(string pdu, ref int index, byte dcs, out byte userDataLength, out byte[] userData)
+ {
+ int num = index;
+ int num1 = num;
+ index = num + 1;
+ byte num2 = BcdWorker.GetByte(pdu, num1);
+ if (num2 <= 0)
+ {
+ userDataLength = 0;
+ userData = new byte[0];
+ return;
+ }
+ else
+ {
+ int remainingUserDataBytes = PduParts.GetRemainingUserDataBytes(num2, dcs);
+ int num3 = BcdWorker.CountBytes(pdu) - index;
+ if (num3 < remainingUserDataBytes)
+ {
+ remainingUserDataBytes = num3;
+ }
+ string bytesString = BcdWorker.GetBytesString(pdu, index, remainingUserDataBytes);
+ index = index + remainingUserDataBytes;
+ string empty = string.Empty;
+ for (int i = 0; i < bytesString.Length / 2; i++)
+ {
+ string byteString = BcdWorker.GetByteString(bytesString, i);
+ if (!Calc.IsHexString(byteString))
+ {
+ break;
+ }
+ empty = string.Concat(empty, byteString);
+ }
+ userDataLength = num2;
+ userData = Calc.HexToInt(empty);
+ return;
+ }
+ }
+
+ ///
+ /// Calculates the number of bytes that must be present in the user data portion of the PDU.
+ ///
+ /// The user data length specified in the PDU.
+ /// The data coding scheme specified in the PDU.
+ /// The number of bytes (octets) that must be present, or, if decoding the user data, the number
+ /// of remaining bytes that must be read.
+ /// The dataLength and dataCodingScheme parameters are used to
+ /// calculate the number of bytes that must be present in the user data.
+ internal static int GetRemainingUserDataBytes(byte dataLength, byte dataCodingScheme)
+ {
+ int num;
+ DataCodingScheme dataCodingScheme1 = DataCodingScheme.Decode(dataCodingScheme);
+ byte alphabet = dataCodingScheme1.Alphabet;
+ switch (alphabet)
+ {
+ case 0:
+ {
+ num = (int)Math.Ceiling((double)dataLength * 7 / 8);
+ break;
+ }
+ case 1:
+ case 2:
+ {
+ num = dataLength;
+ break;
+ }
+ default:
+ {
+ num = (int)Math.Ceiling((double)dataLength * 7 / 8);
+ break;
+ }
+ }
+ return num;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/ProtocolID.cs b/PDUConverter/GsmComm.PduConverter/ProtocolID.cs
new file mode 100644
index 0000000..7301932
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/ProtocolID.cs
@@ -0,0 +1,213 @@
+using System;
+
+///
+/// This class and its contained classes contain all possible values for the
+/// Protocol Identifier.
+///
+/// The members represent the TP-PID octet in the PDU.
+namespace GsmComm.PduConverter
+{
+ public class ProtocolID
+ {
+ private const byte niwOffset = 0;
+
+ private const byte iwOffset = 32;
+
+ private const byte nuOffset = 64;
+
+ private const byte resOffset = 128;
+
+ private const byte scOffset = 192;
+
+ private ProtocolID()
+ {
+ }
+
+ ///
+ /// Extracts the "Reserved" part of the PID.
+ ///
+ /// The PID containing the value.
+ /// The value of the "Reserved" part.
+ /// Value is not from the "Reserved" range.
+ public static byte GetReservedValue(byte pid)
+ {
+ if (ProtocolID.IsReserved(pid))
+ {
+ return (byte)(pid - 128);
+ }
+ else
+ {
+ throw new ArgumentException("Value is not from the \"Reserved\" range.", "pid");
+ }
+ }
+
+ ///
+ /// Gets the "SC Specific Use" part of the ProtocolID.
+ ///
+ /// The PID byte to decode.
+ /// The "SC Specific Use" value.
+ /// Value in pid is not from the "SC specific" range.
+ public static byte GetSCSpecificUseValue(byte pid)
+ {
+ if (ProtocolID.IsSCSpecificUse(pid))
+ {
+ return (byte)(pid - 192);
+ }
+ else
+ {
+ throw new ArgumentException("Value is not from the \"SC specific\" range.", "pid");
+ }
+ }
+
+ ///
+ /// Determines if the specified value is from the "Reserved" part.
+ ///
+ /// The value to check.
+ /// true if the value is from the reserved part, false otherwise.
+ public static bool IsReserved(byte pid)
+ {
+ if (pid < 128)
+ {
+ return false;
+ }
+ else
+ {
+ return pid - 128 <= 63;
+ }
+ }
+
+ ///
+ /// Determines if the specified PID is from the "SC Specific Use" part.
+ ///
+ /// The value to check.
+ /// true if the value is for SC specific use, false otherwise.
+ public static bool IsSCSpecificUse(byte pid)
+ {
+ if (pid < 192)
+ {
+ return false;
+ }
+ else
+ {
+ return pid - 192 <= 63;
+ }
+ }
+
+ ///
+ /// Allows the "Reserved" part of the ProtocolID to be used.
+ ///
+ /// The value for this part.
+ /// Value is greater than 0x3F (63).
+ /// The encoded protocol ID.
+ public static byte Reserved(byte value)
+ {
+ if (value <= 63)
+ {
+ return (byte)(128 + value);
+ }
+ else
+ {
+ throw new ArgumentException("Value must not be greater than 0x3F (63).");
+ }
+ }
+
+ ///
+ /// Allows the "SC Specific Use" part of the ProtocolID to be used.
+ ///
+ /// The value for this part.
+ /// Value is greater than 0x3F (63).
+ /// The encoded Protocol ID.
+ public static byte SCSpecificUse(byte value)
+ {
+ if (value <= 63)
+ {
+ return (byte)(192 + value);
+ }
+ else
+ {
+ throw new ArgumentException("Value must not be greater than 0x3F (63).");
+ }
+ }
+
+ ///
+ /// Telematic interworking.
+ ///
+ ///
+ /// If an interworking protocol is specified in an SMS-SUBMIT PDU,
+ /// it indicates that the SME is a telematic device of the specified type,
+ /// and requests the SC to convert the SM into a form suited for that
+ /// device type. If the destination network is ISDN, the SC must also
+ /// select the proper service indicators for connecting to a device of
+ /// that type.
+ /// If an interworking protocol is specified in an SMS-DELIVER PDU,
+ /// it indicates that the SME is a telematic device of the specified type.
+ ///
+ ///
+ public enum Interworking : byte
+ {
+ Implicit,
+ Telex,
+ Group3Telefax,
+ Group4Telefax,
+ VoiceTelephone,
+ Ermes,
+ PagingSystem,
+ VideoTex,
+ Teletex,
+ TeletexPSPDN,
+ TeletexCSPDN,
+ TeletexPSTN,
+ TeletexISDN,
+ Uci,
+ Reserved0E,
+ Reserved0F,
+ MessageHandler,
+ X400BasedHandler,
+ InternetEMail,
+ Reserved13,
+ Reserved14,
+ Reserved15,
+ Reserved16,
+ Reserved17,
+ SCSpecific1,
+ SCSpecific2,
+ SCSpecific3,
+ SCSpecific4,
+ SCSpecific5,
+ SCSpecific6,
+ SCSpecific7,
+ GsmMobileStation
+ }
+
+ ///
+ /// For network use
+ ///
+ ///
+ /// Details are written in the remarks section of the types.
+ ///
+ public enum NetworkUse : byte
+ {
+ ShortMessageType0,
+ ReplaceShortMessageType1,
+ ReplaceShortMessageType2,
+ ReplaceShortMessageType3,
+ ReplaceShortMessageType4,
+ ReplaceShortMessageType5,
+ ReplaceShortMessageType6,
+ ReplaceShortMessageType7,
+ ReturnCallMessage,
+ MEDataDownload,
+ MEDepersonalization,
+ SIMDataDownload
+ }
+
+ ///
+ /// For the straightforward case of simple MS-to-SC short message
+ /// transfer. No interworking is performed.
+ ///
+ public enum NoInterworking : byte
+ {
+ SmeToSmeProtocol
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/RelativeValidityPeriod.cs b/PDUConverter/GsmComm.PduConverter/RelativeValidityPeriod.cs
new file mode 100644
index 0000000..8b2a575
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/RelativeValidityPeriod.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Text;
+
+///
+/// The relative validity period gives the length of the validity period
+/// counted from when the SMS-SUBMIT is received by the SC.
+///
+namespace GsmComm.PduConverter
+{
+ public class RelativeValidityPeriod : ValidityPeriod
+ {
+ private byte @value;
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The byte value of the validity period. Use this
+ /// if you have already calculated the validity yourself.
+ public RelativeValidityPeriod(byte value)
+ {
+ this.@value = value;
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The validity period.
+ ///
+ /// There are some rules to note:
+ ///
+ /// -
+ /// The smallest validity period is 5 minutes, 63 weeks the largest.
+ ///
+ /// -
+ /// Periods between 5 minutes and 12 hours can be specified in 5 minute steps.
+ ///
+ /// -
+ /// Periods between 12h30min and 24 hours can be specified in 30 minute steps.
+ ///
+ /// -
+ /// Periods between two days and 30 days can be specified in 1 day steps.
+ ///
+ /// -
+ /// Periods between 5 weeks and 63 weeks can be specified in 1 week (=7 days) steps.
+ ///
+ ///
+ ///
+ /// Validity timespan is invalid.
+ public RelativeValidityPeriod(TimeSpan period)
+ {
+ byte num = 0;
+ while (num <= 255)
+ {
+ TimeSpan timeSpan = RelativeValidityPeriod.ToTimeSpan(num);
+ if (timeSpan.CompareTo(period) != 0)
+ {
+ num = (byte)(num + 1);
+ }
+ else
+ {
+ this.@value = num;
+ return;
+ }
+ }
+ throw new ArgumentException("Invalid validity timespan.");
+ }
+
+ private void AppendIfNonzero(StringBuilder str, int val, string suffix)
+ {
+ if (val > 0)
+ {
+ if (str.Length != 0)
+ {
+ str.Append(" ");
+ }
+ str.Append(val.ToString());
+ str.Append(suffix);
+ }
+ }
+
+ public static explicit operator RelativeValidityPeriod(TimeSpan ts)
+ {
+ return new RelativeValidityPeriod(ts);
+ }
+
+ public static implicit operator TimeSpan(RelativeValidityPeriod v)
+ {
+ return v.ToTimeSpan();
+ }
+
+ public static implicit operator Byte(RelativeValidityPeriod v)
+ {
+ return v.ToByte();
+ }
+
+ public static implicit operator RelativeValidityPeriod(byte b)
+ {
+ return new RelativeValidityPeriod(b);
+ }
+
+ ///
+ /// Returns the byte equivalent of this instance.
+ ///
+ /// The byte value.
+ public byte ToByte()
+ {
+ return this.@value;
+ }
+
+ ///
+ /// Returns the string equivalent of this instance.
+ ///
+ public override string ToString()
+ {
+ TimeSpan timeSpan = this.ToTimeSpan();
+ if (timeSpan.TotalHours != 24)
+ {
+ StringBuilder stringBuilder = new StringBuilder();
+ this.AppendIfNonzero(stringBuilder, timeSpan.Days, "d");
+ this.AppendIfNonzero(stringBuilder, timeSpan.Hours, "h");
+ this.AppendIfNonzero(stringBuilder, timeSpan.Minutes, "m");
+ this.AppendIfNonzero(stringBuilder, timeSpan.Seconds, "s");
+ this.AppendIfNonzero(stringBuilder, timeSpan.Milliseconds, "ms");
+ return stringBuilder.ToString();
+ }
+ else
+ {
+ return "24h";
+ }
+ }
+
+ ///
+ /// Returns the TimeSpan equivalent of this instance.
+ ///
+ /// The TimeSpan value.
+ public TimeSpan ToTimeSpan()
+ {
+ return RelativeValidityPeriod.ToTimeSpan(this.@value);
+ }
+
+ private static TimeSpan ToTimeSpan(byte value)
+ {
+ if (value < 0 || value > 143)
+ {
+ if (value < 144 || value > 167)
+ {
+ if (value < 168 || value > 196)
+ {
+ if (value < 197 || value > 255)
+ {
+ return TimeSpan.Zero;
+ }
+ else
+ {
+ return new TimeSpan((value - 192) * 7, 0, 0, 0);
+ }
+ }
+ else
+ {
+ return new TimeSpan(value - 166, 0, 0, 0);
+ }
+ }
+ else
+ {
+ return new TimeSpan(12, (value - 143) * 30, 0);
+ }
+ }
+ else
+ {
+ return new TimeSpan(0, (value + 1) * 5, 0);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/ReservedCodingGroup.cs b/PDUConverter/GsmComm.PduConverter/ReservedCodingGroup.cs
new file mode 100644
index 0000000..b47f2f9
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/ReservedCodingGroup.cs
@@ -0,0 +1,32 @@
+using System;
+
+///
+/// Reserved coding
+///
+namespace GsmComm.PduConverter
+{
+ public class ReservedCodingGroup : DataCodingScheme
+ {
+ private byte dcs;
+
+ ///
+ /// Gets the alphabet being used.
+ ///
+ public override byte Alphabet
+ {
+ get
+ {
+ return 3;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The DCS byte to decode.
+ public ReservedCodingGroup(byte dcs) : base(dcs)
+ {
+ this.dcs = dcs;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/SmartMessaging/ConcatInfoComparer.cs b/PDUConverter/GsmComm.PduConverter/SmartMessaging/ConcatInfoComparer.cs
new file mode 100644
index 0000000..4b66210
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/SmartMessaging/ConcatInfoComparer.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+
+///
+/// Implements a method to compare objects.
+///
+/// This comparer is provided for performing sort order comparisons. It does not perform exact equality comparisons.
+namespace GsmComm.PduConverter.SmartMessaging
+{
+ public class ConcatInfoComparer : IComparer
+ {
+ public ConcatInfoComparer()
+ {
+ }
+
+ ///
+ /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ ///
+ ///
+ ///
+ /// Value
+ /// Condition
+ ///
+ /// -
+ /// Less than zero
+ /// x is less than y.
+ ///
+ /// -
+ /// Zero
+ /// x equals y.
+ ///
+ /// -
+ /// Greater than zero
+ /// x is greater than y.
+ ///
+ ///
+ ///
+ ///
+ /// This method provides a sort order comparison for type .
+ /// Comparing null with any reference type is allowed and does not generate an exception. A null reference
+ /// is considered to be less than any reference that is not null.
+ ///
+ public int Compare(IConcatenationInfo x, IConcatenationInfo y)
+ {
+ int num;
+ if (x != null || y != null)
+ {
+ if (x != null || y == null)
+ {
+ if (x == null || y != null)
+ {
+ if (x.ReferenceNumber != y.ReferenceNumber)
+ {
+ ushort referenceNumber = x.ReferenceNumber;
+ num = referenceNumber.CompareTo(y.ReferenceNumber);
+ }
+ else
+ {
+ byte currentNumber = x.CurrentNumber;
+ num = currentNumber.CompareTo(y.CurrentNumber);
+ }
+ }
+ else
+ {
+ num = 1;
+ }
+ }
+ else
+ {
+ num = -1;
+ }
+ }
+ else
+ {
+ num = 0;
+ }
+ return num;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/SmartMessaging/ConcatMessageElement16.cs b/PDUConverter/GsmComm.PduConverter/SmartMessaging/ConcatMessageElement16.cs
new file mode 100644
index 0000000..c9670e1
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/SmartMessaging/ConcatMessageElement16.cs
@@ -0,0 +1,157 @@
+using System;
+
+///
+/// Implements a Concatenated Short Message Information Element (16-bit reference number)
+///
+/// This element is used to indiate that a message is split into
+/// multiple parts.
+namespace GsmComm.PduConverter.SmartMessaging
+{
+ public class ConcatMessageElement16 : InformationElement, IConcatenationInfo
+ {
+ ///
+ /// The Information Element Identifier (IEI).
+ ///
+ public const byte Identifier = 8;
+
+ private ushort referenceNumber;
+
+ private byte totalMessages;
+
+ private byte currentNumber;
+
+ ///
+ /// Gets the current message number.
+ ///
+ public byte CurrentNumber
+ {
+ get
+ {
+ return this.currentNumber;
+ }
+ }
+
+ ///
+ /// Gets the current message number.
+ ///
+ byte GsmComm.PduConverter.SmartMessaging.IConcatenationInfo.CurrentNumber
+ {
+ get
+ {
+ return this.currentNumber;
+ }
+ }
+
+ ///
+ /// Gets the message reference number.
+ ///
+ ushort GsmComm.PduConverter.SmartMessaging.IConcatenationInfo.ReferenceNumber
+ {
+ get
+ {
+ return this.referenceNumber;
+ }
+ }
+
+ ///
+ /// Gets the total number of parts of the message.
+ ///
+ byte GsmComm.PduConverter.SmartMessaging.IConcatenationInfo.TotalMessages
+ {
+ get
+ {
+ return this.totalMessages;
+ }
+ }
+
+ ///
+ /// Gets the message reference number.
+ ///
+ public ushort ReferenceNumber
+ {
+ get
+ {
+ return this.referenceNumber;
+ }
+ }
+
+ ///
+ /// Gets the total number of parts of the message.
+ ///
+ public byte TotalMessages
+ {
+ get
+ {
+ return this.totalMessages;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The message's reference number, must
+ /// be the same in all parts of the same message.
+ /// The total number of parts of the message.
+ /// The current message number.
+ public ConcatMessageElement16(ushort referenceNumber, byte totalMessages, byte currentNumber)
+ {
+ this.referenceNumber = referenceNumber;
+ this.totalMessages = totalMessages;
+ this.currentNumber = currentNumber;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The information element as a byte array.
+ public ConcatMessageElement16(byte[] element)
+ {
+ if (element != null)
+ {
+ if (element[0] == 8)
+ {
+ byte num = element[1];
+ if (num >= 4)
+ {
+ byte[] numArray = new byte[2];
+ numArray[0] = element[3];
+ numArray[1] = element[2];
+ this.referenceNumber = BitConverter.ToUInt16(numArray, 0);
+ this.totalMessages = element[4];
+ this.currentNumber = element[5];
+ return;
+ }
+ else
+ {
+ throw new FormatException("Information element data must be 4 bytes long.");
+ }
+ }
+ else
+ {
+ throw new ArgumentException("Element is not a Concatenated Short Message Information Element (16-bit reference number).", "element");
+ }
+ }
+ else
+ {
+ throw new ArgumentNullException("element");
+ }
+ }
+
+ ///
+ /// Returns the byte array equivalent of this instance.
+ ///
+ /// The byte array.
+ public override byte[] ToByteArray()
+ {
+ byte[] bytes = BitConverter.GetBytes(this.referenceNumber);
+ byte[] numArray = new byte[6];
+ numArray[0] = 8;
+ numArray[1] = 4;
+ numArray[2] = bytes[1];
+ numArray[3] = bytes[0];
+ numArray[4] = this.totalMessages;
+ numArray[5] = this.currentNumber;
+ return numArray;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/SmartMessaging/ConcatMessageElement8.cs b/PDUConverter/GsmComm.PduConverter/SmartMessaging/ConcatMessageElement8.cs
new file mode 100644
index 0000000..3db0431
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/SmartMessaging/ConcatMessageElement8.cs
@@ -0,0 +1,151 @@
+using System;
+
+///
+/// Implements a Concatenated Short Message Information Element (8-bit reference number)
+///
+/// This element is used to indiate that a message is split into
+/// multiple parts.
+namespace GsmComm.PduConverter.SmartMessaging
+{
+ public class ConcatMessageElement8 : InformationElement, IConcatenationInfo
+ {
+ ///
+ /// The Information Element Identifier (IEI).
+ ///
+ public const byte Identifier = 0;
+
+ private byte referenceNumber;
+
+ private byte totalMessages;
+
+ private byte currentNumber;
+
+ ///
+ /// Gets the current message number.
+ ///
+ public byte CurrentNumber
+ {
+ get
+ {
+ return this.currentNumber;
+ }
+ }
+
+ ///
+ /// Gets the current message number.
+ ///
+ byte GsmComm.PduConverter.SmartMessaging.IConcatenationInfo.CurrentNumber
+ {
+ get
+ {
+ return this.currentNumber;
+ }
+ }
+
+ ///
+ /// Gets the message reference number.
+ ///
+ ushort GsmComm.PduConverter.SmartMessaging.IConcatenationInfo.ReferenceNumber
+ {
+ get
+ {
+ return this.referenceNumber;
+ }
+ }
+
+ ///
+ /// Gets the total number of parts of the message.
+ ///
+ byte GsmComm.PduConverter.SmartMessaging.IConcatenationInfo.TotalMessages
+ {
+ get
+ {
+ return this.totalMessages;
+ }
+ }
+
+ ///
+ /// Gets the message reference number.
+ ///
+ public byte ReferenceNumber
+ {
+ get
+ {
+ return this.referenceNumber;
+ }
+ }
+
+ ///
+ /// Gets the total number of parts of the message.
+ ///
+ public byte TotalMessages
+ {
+ get
+ {
+ return this.totalMessages;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The message's reference number, must
+ /// be the same in all parts of the same message.
+ /// The total number of parts of the message.
+ /// The current message number.
+ public ConcatMessageElement8(byte referenceNumber, byte totalMessages, byte currentNumber)
+ {
+ this.referenceNumber = referenceNumber;
+ this.totalMessages = totalMessages;
+ this.currentNumber = currentNumber;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The information element as a byte array.
+ public ConcatMessageElement8(byte[] element)
+ {
+ if (element != null)
+ {
+ if (element[0] == 0)
+ {
+ byte num = element[1];
+ if (num >= 3)
+ {
+ this.referenceNumber = element[2];
+ this.totalMessages = element[3];
+ this.currentNumber = element[4];
+ return;
+ }
+ else
+ {
+ throw new FormatException("Information element data must be 3 bytes long.");
+ }
+ }
+ else
+ {
+ throw new ArgumentException("Element is not a Concatenated Short Message Information Element (8-bit reference number).", "element");
+ }
+ }
+ else
+ {
+ throw new ArgumentNullException("element");
+ }
+ }
+
+ ///
+ /// Returns the byte array equivalent of this instance.
+ ///
+ /// The byte array.
+ public override byte[] ToByteArray()
+ {
+ byte[] numArray = new byte[5];
+ numArray[1] = 3;
+ numArray[2] = this.referenceNumber;
+ numArray[3] = this.totalMessages;
+ numArray[4] = this.currentNumber;
+ return numArray;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/SmartMessaging/IConcatenationInfo.cs b/PDUConverter/GsmComm.PduConverter/SmartMessaging/IConcatenationInfo.cs
new file mode 100644
index 0000000..fdead30
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/SmartMessaging/IConcatenationInfo.cs
@@ -0,0 +1,35 @@
+using System;
+
+///
+/// A common interface for all information elements containing concatenation information.
+///
+namespace GsmComm.PduConverter.SmartMessaging
+{
+ public interface IConcatenationInfo
+ {
+ ///
+ /// Gets the current message number.
+ ///
+ byte CurrentNumber
+ {
+ get;
+ }
+
+ ///
+ /// Gets the message reference number.
+ ///
+ ushort ReferenceNumber
+ {
+ get;
+ }
+
+ ///
+ /// Gets the total number of parts of the message.
+ ///
+ byte TotalMessages
+ {
+ get;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/SmartMessaging/InformationElement.cs b/PDUConverter/GsmComm.PduConverter/SmartMessaging/InformationElement.cs
new file mode 100644
index 0000000..10aa5f8
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/SmartMessaging/InformationElement.cs
@@ -0,0 +1,33 @@
+using GsmComm.PduConverter;
+using System;
+
+///
+/// Implements the base for an information element.
+///
+namespace GsmComm.PduConverter.SmartMessaging
+{
+ public abstract class InformationElement
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ protected InformationElement()
+ {
+ }
+
+ ///
+ /// In the derived classes, returns the byte array equivalent of this instance.
+ ///
+ /// The byte array.
+ public abstract byte[] ToByteArray();
+
+ ///
+ /// Returns the string equivalent of this instance, which is a hexadecimal representation of the element.
+ ///
+ /// The string.
+ public override string ToString()
+ {
+ return Calc.IntToHex(this.ToByteArray());
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/SmartMessaging/OtaBitmap.cs b/PDUConverter/GsmComm.PduConverter/SmartMessaging/OtaBitmap.cs
new file mode 100644
index 0000000..9178712
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/SmartMessaging/OtaBitmap.cs
@@ -0,0 +1,312 @@
+using System;
+using System.Collections;
+using System.Drawing;
+
+///
+/// Represents an OTA (over-the-air) bitmap.
+///
+namespace GsmComm.PduConverter.SmartMessaging
+{
+ public class OtaBitmap
+ {
+ private byte[] bitmap;
+
+ private byte infoField;
+
+ private byte width;
+
+ private byte height;
+
+ private byte grayscales;
+
+ private int dataStart;
+
+ private int dataLen;
+
+ ///
+ /// Gets the actual bitmap data.
+ ///
+ public byte[] Data
+ {
+ get
+ {
+ byte[] numArray = new byte[this.dataLen];
+ Array.Copy(this.bitmap, this.dataStart, numArray, 0, this.dataLen);
+ return numArray;
+ }
+ }
+
+ ///
+ /// Gets the bitmap's height.
+ ///
+ public byte Height
+ {
+ get
+ {
+ return this.height;
+ }
+ }
+
+ ///
+ /// Gets the bitmap's InfoField.
+ ///
+ public byte InfoField
+ {
+ get
+ {
+ return this.infoField;
+ }
+ }
+
+ ///
+ /// Gets the bitmap's number of grayscales.
+ ///
+ public byte NumGrayscales
+ {
+ get
+ {
+ return this.grayscales;
+ }
+ }
+
+ ///
+ /// Gets the bitmap's width.
+ ///
+ public byte Width
+ {
+ get
+ {
+ return this.width;
+ }
+ }
+
+ ///
+ /// Creates a new OTA bitmap from an existing object.
+ ///
+ /// The to create the OTA bitmap from.
+ public OtaBitmap(Bitmap bitmap) : this(OtaBitmap.BitmapToOtaBitmap(bitmap))
+ {
+ }
+
+ ///
+ /// Creates a new OTA bitmap from an existing byte array.
+ ///
+ /// The byte array containing the OTA bitmap.
+ /// otaBitmap is null.
+ public OtaBitmap(byte[] otaBitmap)
+ {
+ if (otaBitmap != null)
+ {
+ int num = 0;
+ int num1 = num;
+ num = num1 + 1;
+ this.infoField = otaBitmap[num1];
+ int num2 = num;
+ num = num2 + 1;
+ this.width = otaBitmap[num2];
+ int num3 = num;
+ num = num3 + 1;
+ this.height = otaBitmap[num3];
+ int num4 = num;
+ num = num4 + 1;
+ this.grayscales = otaBitmap[num4];
+ this.dataStart = num;
+ this.dataLen = (int)otaBitmap.Length - num;
+ this.bitmap = new byte[(int)otaBitmap.Length];
+ otaBitmap.CopyTo(this.bitmap, 0);
+ return;
+ }
+ else
+ {
+ throw new ArgumentException("otaBitmap");
+ }
+ }
+
+ ///
+ /// Converts a into an OTA (over-the-air) bitmap.
+ ///
+ /// The to convert. The maximum allowed
+ /// size is 255x255 pixels, minimum is 1x1. The bitmap can be any
+ /// pixel format, but only the black pixels are converted.
+ /// Can be null to get an empty header.
+ /// The converted image. If bitmap is null, an empty OTA bitmap
+ /// header and no data is returned.
+ /// bitmap is greater than 255x255 pixels.
+ private static byte[] BitmapToOtaBitmap(Bitmap bitmap)
+ {
+ byte[] numArray = null;
+ byte[] numArray1 = null;
+ if (bitmap == null)
+ {
+ numArray1 = new byte[0];
+ byte[] numArray2 = new byte[4];
+ numArray2[3] = 1;
+ numArray = numArray2;
+ }
+ else
+ {
+ if (bitmap.Height < 1 || bitmap.Width < 1 || bitmap.Height > 255 || bitmap.Width > 255)
+ {
+ throw new ArgumentException("Invalid bitmap dimensions. Maximum size is 255x255, minimum size is 1x1 pixels.");
+ }
+ else
+ {
+ int num = 7;
+ byte num1 = 0;
+ ArrayList arrayLists = new ArrayList();
+ for (int i = 0; i < bitmap.Height; i++)
+ {
+ for (int j = 0; j < bitmap.Width; j++)
+ {
+ byte num2 = (byte)Math.Pow(2, (double)num);
+ Color pixel = bitmap.GetPixel(j, i);
+ Color black = Color.Black;
+ if (pixel.ToArgb() == black.ToArgb())
+ {
+ num1 = (byte)(num1 | num2);
+ }
+ if (num != 0)
+ {
+ num--;
+ }
+ else
+ {
+ arrayLists.Add(num1);
+ num1 = 0;
+ num = 7;
+ }
+ }
+ }
+ if (num < 7)
+ {
+ arrayLists.Add(num1);
+ }
+ numArray1 = new byte[arrayLists.Count];
+ arrayLists.CopyTo(numArray1);
+ byte[] width = new byte[4];
+ width[1] = (byte)bitmap.Width;
+ width[2] = (byte)bitmap.Height;
+ width[3] = 1;
+ numArray = width;
+ }
+ }
+ byte[] numArray3 = new byte[(int)numArray.Length + (int)numArray1.Length];
+ numArray.CopyTo(numArray3, 0);
+ numArray1.CopyTo(numArray3, (int)numArray.Length);
+ return numArray3;
+ }
+
+ public static explicit operator Bitmap(OtaBitmap b)
+ {
+ return b.ToBitmap();
+ }
+
+ public static explicit operator OtaBitmap(Bitmap b)
+ {
+ return new OtaBitmap(b);
+ }
+
+ public static explicit operator OtaBitmap(byte[] b)
+ {
+ return new OtaBitmap(b);
+ }
+
+ public static implicit operator Byte[](OtaBitmap b)
+ {
+ return b.ToByteArray();
+ }
+
+ ///
+ /// Converts an OTA bitmap into a .
+ ///
+ /// The OTA bitmap to convert. Can be null.
+ /// The converted image. If otaBitmap is null, null is returned.
+ /// null is also returned, if the height or width of the OTA bitmap is 0.
+ ///
+ /// The grayscales attribute of the bitmap is ignored, always a monochrome bitmap is created.
+ ///
+ private static Bitmap OtaBitmapToBitmap(byte[] otaBitmap)
+ {
+ Color black;
+ if (otaBitmap != null)
+ {
+ int num = 0;
+ int num1 = num;
+ num = num1 + 1;
+ int num2 = num;
+ num = num2 + 1;
+ byte num3 = otaBitmap[num2];
+ int num4 = num;
+ num = num4 + 1;
+ byte num5 = otaBitmap[num4];
+ int num6 = num;
+ num = num6 + 1;
+ if (num3 == 0 || num5 == 0)
+ {
+ return null;
+ }
+ else
+ {
+ Bitmap bitmap = new Bitmap(num3, num5);
+ int num7 = 0;
+ byte num8 = 0;
+ for (int i = 0; i < num5; i++)
+ {
+ for (int j = 0; j < num3; j++)
+ {
+ if (num7 != 0)
+ {
+ num7--;
+ }
+ else
+ {
+ int num9 = num;
+ num = num9 + 1;
+ num8 = otaBitmap[num9];
+ num7 = 7;
+ }
+ byte num10 = (byte)Math.Pow(2, (double)num7);
+ Bitmap bitmap1 = bitmap;
+ int num11 = j;
+ int num12 = i;
+ if ((num8 & num10) > 0)
+ {
+ black = Color.Black;
+ }
+ else
+ {
+ black = Color.White;
+ }
+ bitmap1.SetPixel(num11, num12, black);
+ }
+ }
+ return bitmap;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// Returns the equivalent of this instance.
+ ///
+ /// The .
+ public Bitmap ToBitmap()
+ {
+ return OtaBitmap.OtaBitmapToBitmap(this.bitmap);
+ }
+
+ ///
+ /// Returns the byte array equivalent of this instance.
+ ///
+ /// The byte array.
+ public byte[] ToByteArray()
+ {
+ byte[] numArray = new byte[(int)this.bitmap.Length];
+ this.bitmap.CopyTo(numArray, 0);
+ return numArray;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/SmartMessaging/PortAddressElement16.cs b/PDUConverter/GsmComm.PduConverter/SmartMessaging/PortAddressElement16.cs
new file mode 100644
index 0000000..85ea0f5
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/SmartMessaging/PortAddressElement16.cs
@@ -0,0 +1,111 @@
+using System;
+
+///
+/// Implements an Application Port Addressing Information Element (16 bit address).
+///
+/// This element is used to indiate from which port a message
+/// originated and to which port it should be directed to.
+namespace GsmComm.PduConverter.SmartMessaging
+{
+ public class PortAddressElement16 : InformationElement
+ {
+ ///
+ /// The Information Element Identifier (IEI).
+ ///
+ public const byte Identifier = 5;
+
+ private ushort destinationPort;
+
+ private ushort originatorPort;
+
+ ///
+ /// Gets the destination port.
+ ///
+ public ushort DestinationPort
+ {
+ get
+ {
+ return this.destinationPort;
+ }
+ }
+
+ ///
+ /// Gets the originator port.
+ ///
+ public ushort OriginatorPort
+ {
+ get
+ {
+ return this.originatorPort;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The destination port, e.g. 0x1582.
+ /// The source port, e.g. 0x00.
+ public PortAddressElement16(ushort destinationPort, ushort originatorPort)
+ {
+ this.destinationPort = destinationPort;
+ this.originatorPort = originatorPort;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The information element as a byte array.
+ public PortAddressElement16(byte[] element)
+ {
+ if (element != null)
+ {
+ if (element[0] == 5)
+ {
+ byte num = element[1];
+ if (num >= 4)
+ {
+ byte[] numArray = new byte[2];
+ numArray[0] = element[3];
+ numArray[1] = element[2];
+ this.destinationPort = BitConverter.ToUInt16(numArray, 0);
+ byte[] numArray1 = new byte[2];
+ numArray1[0] = element[5];
+ numArray1[1] = element[4];
+ this.originatorPort = BitConverter.ToUInt16(numArray1, 0);
+ return;
+ }
+ else
+ {
+ throw new FormatException("Information element data must be 4 bytes long.");
+ }
+ }
+ else
+ {
+ throw new ArgumentException("Element is not an Application Port Addressing Information Element (16 bit address).", "element");
+ }
+ }
+ else
+ {
+ throw new ArgumentNullException("element");
+ }
+ }
+
+ ///
+ /// Returns the byte array equivalent of this instance.
+ ///
+ /// The byte array.
+ public override byte[] ToByteArray()
+ {
+ byte[] bytes = BitConverter.GetBytes(this.destinationPort);
+ byte[] numArray = BitConverter.GetBytes(this.originatorPort);
+ byte[] numArray1 = new byte[6];
+ numArray1[0] = 5;
+ numArray1[1] = 4;
+ numArray1[2] = bytes[1];
+ numArray1[3] = bytes[0];
+ numArray1[4] = numArray[1];
+ numArray1[5] = numArray[0];
+ return numArray1;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PDUConverter/GsmComm.PduConverter/SmartMessaging/SmartMessageDecoder.cs b/PDUConverter/GsmComm.PduConverter/SmartMessaging/SmartMessageDecoder.cs
new file mode 100644
index 0000000..1d79869
--- /dev/null
+++ b/PDUConverter/GsmComm.PduConverter/SmartMessaging/SmartMessageDecoder.cs
@@ -0,0 +1,470 @@
+using GsmComm.PduConverter;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+///
+/// Decodes messages based on Nokia's Smart Messaging specification and related messages.
+///
+///
+/// This methods in this class can be used to find and combine concatenated (long, multi-part) SMS messages.
+/// To determine, whether a message is part of a concatenated message at all, use
+/// When you have identified that a message is a part of a concatenated message, you need to find the other message parts
+/// belonging to the same message, can be used for this.
+///
+/// After all parts of the concatenated message have been identified, the parts need to be combined. This is done
+/// using and . The difference between these two
+/// methods is, that the first one returns the combined data in binary format, whereas the latter returns the result
+/// as text.
+/// To verify that all message parts are present before attempting to combine them,
+/// can be used. Calling this method is optional, but prevents exceptions when combining without all parts present.
+/// The above methods all accept instances to abstract some of the work that has to be done
+/// to find and combine concatenated SMS messages. However, it is also possible to retrieve the underlying data that
+/// is used for these operations (and also possible for other operations as well) using the methods
+/// and .
+///
+namespace GsmComm.PduConverter.SmartMessaging
+{
+ public class SmartMessageDecoder
+ {
+ public SmartMessageDecoder()
+ {
+ }
+
+ ///
+ /// Determines whether all parts of a concatenated message are present.
+ ///
+ /// The parts that make up the concatenated message.
+ /// true if all parts are present, false otherwise.
+ /// parts is null.
+ ///
+ /// The reference numbers differ between the message parts.
+ /// -or-
+ /// The number of total messages differs between the message parts.
+ /// -or-
+ /// A non-concatenated message part is present at an invalid position.
+ ///
+ public static bool AreAllConcatPartsPresent(IList parts)
+ {
+ bool flag = false;
+ SmartMessageDecoder.GetConcatUserData(parts, false, true, true, out flag);
+ return flag;
+ }
+
+ ///
+ /// Determines whether two messages are part of the same concatenated message.
+ ///
+ /// The first message to compare.
+ /// The second message to compare.
+ /// true if both messages appear to belong to the same concatenated message, false otherwise.
+ ///
+ /// This comparison is supported for and objects.
+ /// For all other objects, this comparison always returns false.
+ /// For objects, the ,
+ /// and properties are compared.
+ /// For objects, the ,
+ /// and properties are compared.
+ ///
+ /// pdu1 or pdu2 is null.
+ public static bool ArePartOfSameMessage(SmsPdu pdu1, SmsPdu pdu2)
+ {
+ if (pdu1 != null)
+ {
+ if (pdu2 != null)
+ {
+ bool flag = false;
+ if (pdu1 as SmsDeliverPdu == null || pdu2 as SmsDeliverPdu == null)
+ {
+ if (pdu1 is SmsSubmitPdu && pdu2 is SmsSubmitPdu)
+ {
+ SmsSubmitPdu smsSubmitPdu = (SmsSubmitPdu)pdu1;
+ SmsSubmitPdu smsSubmitPdu1 = (SmsSubmitPdu)pdu2;
+ if (smsSubmitPdu.DestinationAddress == smsSubmitPdu1.DestinationAddress && smsSubmitPdu.DestinationAddressType == smsSubmitPdu1.DestinationAddressType)
+ {
+ flag = SmartMessageDecoder.HaveSameReferenceNumber(pdu1, pdu2);
+ }
+ }
+ }
+ else
+ {
+ SmsDeliverPdu smsDeliverPdu = (SmsDeliverPdu)pdu1;
+ SmsDeliverPdu smsDeliverPdu1 = (SmsDeliverPdu)pdu2;
+ if (smsDeliverPdu.OriginatingAddress == smsDeliverPdu1.OriginatingAddress && smsDeliverPdu.OriginatingAddressType == smsDeliverPdu1.OriginatingAddressType)
+ {
+ flag = SmartMessageDecoder.HaveSameReferenceNumber(pdu1, pdu2);
+ }
+ }
+ return flag;
+ }
+ else
+ {
+ throw new ArgumentNullException("pdu2");
+ }
+ }
+ else
+ {
+ throw new ArgumentNullException("pdu1");
+ }
+ }
+
+ ///
+ /// Combines the parts of a concatenated message into a single message.
+ ///
+ /// The parts that make up the concatenated message.
+ /// A byte array containing the combined user data of all parts without any headers.
+ ///
+ /// All parts must be available, but can be in any order.
+ /// The user data is returned in its binary format. If you want the user data to be
+ /// returned as text, use instead.
+ /// If the first part is a non-concatenated message, its user data is returned back, and no more parts are processed
+ /// afterwards.
+ ///
+ /// parts is null.
+ ///
+ /// Not all parts of the message are available.
+ /// -or-
+ /// The reference numbers differ between the message parts.
+ /// -or-
+ /// The number of total messages differs between the message parts.
+ /// -or-
+ /// A non-concatenated message part is present at an invalid position.
+ ///
+ ///
+ public static byte[] CombineConcatMessage(IList parts)
+ {
+ bool flag = false;
+ List