/******************************************************
Simple MAPI.NET
netmaster@swissonline.ch
*******************************************************/
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace Win32Mapi
{
public class Mapi
{
#region SESSION
// ----------------------------------------------------------- SESSION ---------
public bool Logon( IntPtr hwnd )
{
winhandle = hwnd;
error = MAPILogon( hwnd, null, null, 0, 0, ref session );
if( error != 0 )
error = MAPILogon( hwnd, null, null, MapiLogonUI, 0, ref session );
return error == 0;
}
public void Reset()
{
findseed = null;
origin = new MapiRecipDesc();
recpts.Clear();
attachs.Clear();
lastMsg = null;
}
public void Logoff()
{
if( session != IntPtr.Zero )
{
error = MAPILogoff( session, winhandle, 0, 0 );
session = IntPtr.Zero;
}
}
[DllImport( "MAPI32.DLL", CharSet=CharSet.Ansi)]
private static extern int MAPILogon( IntPtr hwnd, string prf, string pw,
int flg, int rsv, ref IntPtr sess );
[DllImport( "MAPI32.DLL")]
private static extern int MAPILogoff( IntPtr sess, IntPtr hwnd,
int flg, int rsv );
private const int MapiLogonUI = 0x00000001;
private const int MapiPasswordUI = 0x00020000;
private const int MapiNewSession = 0x00000002;
private const int MapiForceDownload = 0x00001000;
private const int MapiExtendedUI = 0x00000020;
private IntPtr session = IntPtr.Zero;
private IntPtr winhandle = IntPtr.Zero;
#endregion
#region SENDING
// ----------------------------------------------------------- SENDING ---------
public bool Send( string sub, string txt )
{
lastMsg = new MapiMessage();
lastMsg.subject = sub;
lastMsg.noteText = txt;
// set pointers
lastMsg.originator = AllocOrigin();
lastMsg.recips = AllocRecips( out lastMsg.recipCount );
lastMsg.files = AllocAttachs( out lastMsg.fileCount );
error = MAPISendMail( session, winhandle, lastMsg, 0, 0 );
Dealloc();
Reset();
return error == 0;
}
public void AddRecip( string name, string addr, bool cc )
{
MapiRecipDesc dest = new MapiRecipDesc();
if( cc )
dest.recipClass = MapiCC;
else
dest.recipClass = MapiTO;
dest.name = name;
dest.address = addr;
recpts.Add( dest );
}
public void SetSender( string sname, string saddr )
{
origin.name = sname;
origin.address = saddr;
}
public void Attach( string filepath )
{
attachs.Add( filepath );
}
private IntPtr AllocOrigin()
{
origin.recipClass = MapiORIG;
Type rtype = typeof(MapiRecipDesc);
int rsize = Marshal.SizeOf( rtype );
IntPtr ptro = Marshal.AllocHGlobal( rsize );
Marshal.StructureToPtr( origin, ptro, false );
return ptro;
}
private IntPtr AllocRecips( out int recipCount )
{
recipCount = 0;
if( recpts.Count == 0 )
return IntPtr.Zero;
Type rtype = typeof(MapiRecipDesc);
int rsize = Marshal.SizeOf( rtype );
IntPtr ptrr = Marshal.AllocHGlobal( recpts.Count * rsize );
int runptr = (int) ptrr;
for( int i = 0; i < recpts.Count; i++ )
{
Marshal.StructureToPtr( recpts[i] as MapiRecipDesc, (IntPtr) runptr, false );
runptr += rsize;
}
recipCount = recpts.Count;
return ptrr;
}
private IntPtr AllocAttachs( out int fileCount )
{
fileCount = 0;
if( attachs == null )
return IntPtr.Zero;
if( (attachs.Count <= 0) || (attachs.Count > 100) )
return IntPtr.Zero;
Type atype = typeof(MapiFileDesc);
int asize = Marshal.SizeOf( atype );
IntPtr ptra = Marshal.AllocHGlobal( attachs.Count * asize );
MapiFileDesc mfd = new MapiFileDesc();
mfd.position = -1;
int runptr = (int) ptra;
for( int i = 0; i < attachs.Count; i++ )
{
string path = attachs[i] as string;
mfd.name = Path.GetFileName( path );
mfd.path = path;
Marshal.StructureToPtr( mfd, (IntPtr) runptr, false );
runptr += asize;
}
fileCount = attachs.Count;
return ptra;
}
private void Dealloc()
{
Type rtype = typeof(MapiRecipDesc);
int rsize = Marshal.SizeOf( rtype );
if( lastMsg.originator != IntPtr.Zero )
{
Marshal.DestroyStructure( lastMsg.originator, rtype );
Marshal.FreeHGlobal( lastMsg.originator );
}
if( lastMsg.recips != IntPtr.Zero )
{
int runptr = (int) lastMsg.recips;
for( int i = 0; i < lastMsg.recipCount; i++ )
{
Marshal.DestroyStructure( (IntPtr) runptr, rtype );
runptr += rsize;
}
Marshal.FreeHGlobal( lastMsg.recips );
}
if( lastMsg.files != IntPtr.Zero )
{
Type ftype = typeof(MapiFileDesc);
int fsize = Marshal.SizeOf( ftype );
int runptr = (int) lastMsg.files;
for( int i = 0; i < lastMsg.fileCount; i++ )
{
Marshal.DestroyStructure( (IntPtr) runptr, ftype );
runptr += fsize;
}
Marshal.FreeHGlobal( lastMsg.files );
}
}
private const int MapiORIG = 0;
private const int MapiTO = 1;
private const int MapiCC = 2;
private const int MapiBCC = 3;
[DllImport( "MAPI32.DLL")]
private static extern int MAPISendMail( IntPtr sess, IntPtr hwnd,
MapiMessage message,
int flg, int rsv );
private MapiRecipDesc origin = new MapiRecipDesc();
private ArrayList recpts = new ArrayList();
private ArrayList attachs = new ArrayList();
#endregion
#region FINDING
// ----------------------------------------------------------- FINDING ---------
public bool Next( ref MailEnvelop env )
{
error = MAPIFindNext( session, winhandle, null, findseed,
MapiLongMsgID, 0, lastMsgID );
if( error != 0 )
return false;
findseed = lastMsgID.ToString();
IntPtr ptrmsg = IntPtr.Zero;
error = MAPIReadMail( session, winhandle, findseed,
MapiEnvOnly | MapiPeek | MapiSuprAttach, 0, ref ptrmsg );
if( (error != 0) || (ptrmsg == IntPtr.Zero) )
return false;
lastMsg = new MapiMessage();
Marshal.PtrToStructure( ptrmsg, lastMsg );
MapiRecipDesc orig = new MapiRecipDesc();
if( lastMsg.originator != IntPtr.Zero )
Marshal.PtrToStructure( lastMsg.originator, orig );
env.id = findseed;
env.date = DateTime.ParseExact( lastMsg.dateReceived, "yyyy/MM/dd HH:mm", DateTimeFormatInfo.InvariantInfo );
env.subject = lastMsg.subject;
env.from = orig.name;
env.unread = (lastMsg.flags & MapiUnread) != 0;
env.atts = lastMsg.fileCount;
error = MAPIFreeBuffer( ptrmsg );
return error == 0;
}
[DllImport( "MAPI32.DLL", CharSet=CharSet.Ansi)]
private static extern int MAPIFindNext( IntPtr sess, IntPtr hwnd, string typ,
string seed, int flg, int rsv, StringBuilder id );
private const int MapiUnreadOnly = 0x00000020;
private const int MapiGuaranteeFiFo = 0x00000100;
private const int MapiLongMsgID = 0x00004000;
private StringBuilder lastMsgID = new StringBuilder( 600 );
private string findseed = null;
#endregion
#region READING
// ----------------------------------------------------------- READING ---------
public string Read( string id, out MailAttach[] aat )
{
aat = null;
IntPtr ptrmsg = IntPtr.Zero;
error = MAPIReadMail( session, winhandle, id,
MapiPeek | MapiSuprAttach, 0, ref ptrmsg );
if( (error != 0) || (ptrmsg == IntPtr.Zero) )
return null;
lastMsg = new MapiMessage();
Marshal.PtrToStructure( ptrmsg, lastMsg );
if( (lastMsg.fileCount > 0) && (lastMsg.fileCount < 100) && (lastMsg.files != IntPtr.Zero) )
GetAttachNames( out aat );
MAPIFreeBuffer( ptrmsg );
return lastMsg.noteText;
}
public bool Delete( string id )
{
error = MAPIDeleteMail( session, winhandle, id, 0, 0 );
return error == 0;
}
public bool SaveAttachm( string id, string name, string savepath )
{
IntPtr ptrmsg = IntPtr.Zero;
error = MAPIReadMail( session, winhandle, id,
MapiPeek, 0, ref ptrmsg );
if( (error != 0) || (ptrmsg == IntPtr.Zero) )
return false;
lastMsg = new MapiMessage();
Marshal.PtrToStructure( ptrmsg, lastMsg );
bool f = false;
if( (lastMsg.fileCount > 0) && (lastMsg.fileCount < 100) && (lastMsg.files != IntPtr.Zero) )
f = SaveAttachByName( name, savepath );
MAPIFreeBuffer( ptrmsg );
return f;
}
private void GetAttachNames( out MailAttach[] aat )
{
aat = new MailAttach[ lastMsg.fileCount ];
Type fdtype = typeof(MapiFileDesc);
int fdsize = Marshal.SizeOf( fdtype );
MapiFileDesc fdtmp = new MapiFileDesc();
int runptr = (int) lastMsg.files;
for( int i = 0; i < lastMsg.fileCount; i++ )
{
Marshal.PtrToStructure( (IntPtr) runptr, fdtmp );
runptr += fdsize;
aat[i] = new MailAttach();
if( fdtmp.flags == 0 )
{
aat[i].position = fdtmp.position;
aat[i].name = fdtmp.name;
aat[i].path = fdtmp.path;
}
}
}
private bool SaveAttachByName( string name, string savepath )
{
bool f = true;
Type fdtype = typeof(MapiFileDesc);
int fdsize = Marshal.SizeOf( fdtype );
MapiFileDesc fdtmp = new MapiFileDesc();
int runptr = (int) lastMsg.files;
for( int i = 0; i < lastMsg.fileCount; i++ )
{
Marshal.PtrToStructure( (IntPtr) runptr, fdtmp );
runptr += fdsize;
if( fdtmp.flags != 0 )
continue;
if( fdtmp.name == null )
continue;
try {
if( name == fdtmp.name )
{
if( File.Exists( savepath ) )
File.Delete( savepath );
File.Move( fdtmp.path, savepath );
}
}
catch( Exception )
{ f = false; error = 13; }
try {
File.Delete( fdtmp.path );
}
catch( Exception )
{}
}
return f;
}
[DllImport( "MAPI32.DLL", CharSet=CharSet.Ansi)]
private static extern int MAPIReadMail( IntPtr sess, IntPtr hwnd, string id,
int flg, int rsv, ref IntPtr ptrmsg );
[DllImport( "MAPI32.DLL")]
private static extern int MAPIFreeBuffer( IntPtr ptr );
[DllImport( "MAPI32.DLL", CharSet=CharSet.Ansi)]
private static extern int MAPIDeleteMail( IntPtr sess, IntPtr hwnd, string id,
int flg, int rsv );
private const int MapiPeek = 0x00000080;
private const int MapiSuprAttach = 0x00000800;
private const int MapiEnvOnly = 0x00000040;
private const int MapiBodyAsFile = 0x00000200;
private const int MapiUnread = 0x00000001;
private const int MapiReceiptReq = 0x00000002;
private const int MapiSent = 0x00000004;
private MapiMessage lastMsg = null;
#endregion
#region ADDRESS
public bool SingleAddress( string label, out string name, out string addr )
{
name = null;
addr = null;
int newrec = 0;
IntPtr ptrnew = IntPtr.Zero;
error = MAPIAddress( session, winhandle, null, 1, label, 0, IntPtr.Zero,
0, 0, ref newrec, ref ptrnew );
if( (error != 0) || (newrec < 1) || (ptrnew == IntPtr.Zero) )
return false;
MapiRecipDesc recip = new MapiRecipDesc();
Marshal.PtrToStructure( ptrnew, recip );
name = recip.name;
addr = recip.address;
MAPIFreeBuffer( ptrnew );
return true;
}
[DllImport( "MAPI32.DLL", CharSet=CharSet.Ansi)]
private static extern int MAPIAddress( IntPtr sess, IntPtr hwnd, string caption,
int editfld, string labels, int recipcount, IntPtr ptrrecips,
int flg, int rsv, ref int newrec, ref IntPtr ptrnew );
#endregion
#region ERRORS
// ----------------------------------------------------------- ERRORS ---------
public string Error()
{
if( error <= 26 )
return errors[ error ];
return "?unknown? [" + error.ToString() + "]";
}
private int error = 0;
private readonly string[] errors = new string[] {
"OK [0]", "User abort [1]", "General MAPI failure [2]", "MAPI login failure [3]",
"Disk full [4]", "Insufficient memory [5]", "Access denied [6]", "-unknown- [7]",
"Too many sessions [8]", "Too many files were specified [9]", "Too many recipients were specified [10]", "A specified attachment was not found [11]",
"Attachment open failure [12]", "Attachment write failure [13]", "Unknown recipient [14]", "Bad recipient type [15]",
"No messages [16]", "Invalid message [17]", "Text too large [18]", "Invalid session [19]",
"Type not supported [20]", "A recipient was specified ambiguously [21]", "Message in use [22]", "Network failure [23]",
"Invalid edit fields [24]", "Invalid recipients [25]", "Not supported [26]"
};
#endregion
}
// ********************************************* MAPI STRUCTURES *********************************************
[StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public class MapiMessage
{
public int reserved;
public string subject;
public string noteText;
public string messageType;
public string dateReceived;
public string conversationID;
public int flags;
public IntPtr originator; // MapiRecipDesc* [1]
public int recipCount;
public IntPtr recips; // MapiRecipDesc* [n]
public int fileCount;
public IntPtr files; // MapiFileDesc* [n]
}
[StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public class MapiRecipDesc
{
public int reserved;
public int recipClass;
public string name;
public string address;
public int eIDSize;
public IntPtr entryID; // void*
}
[StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public class MapiFileDesc
{
public int reserved;
public int flags;
public int position;
public string path;
public string name;
public IntPtr type;
}
// ********************************************* HELPER STRUCTURES *********************************************
public class MailEnvelop
{
public string id;
public DateTime date;
public string from;
public string subject;
public bool unread;
public int atts;
}
public class MailAttach
{
public int position;
public string path;
public string name;
}
}