Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Now that we have handled the Upload and Delete events, let us handle the Restore event. Implemented in a class library which contains similar classes as the earlier library. Again we have a BaseEventSink class which is extended from the default available with the event handler toolkit and the EventSinkdata class
/*=====================================================================
File: BaseEventSink.cs
Summary: Base class for cached event sinks.
---------------------------------------------------------------------
=====================================================================*/
using System;
using System.Xml;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.IO;
using System.Diagnostics;
using System.Text;
using System.Collections;
using System.Collections.Specialized;
using Microsoft.SharePoint;
using RecycleBin.SharePoint.Configuration;
namespace RecycleBin.SharePoint.EventSink
{
/// <summary>
/// Base class for cached event sinks.
/// Handles impersonation and caching event sink classes to handle multiple events on
/// the same list.
/// </summary>
public class BaseEventSink : Microsoft.SharePoint.IListEventSink
{
public BaseEventSink()
{
}
/// <summary>
/// Implementation of the OnEvent method. Windows SharePoint Services will
/// call this method when an event occurs.
/// </summary>
/// <param name="listEvent">The SPListEvent object that describes the event which occured.</param>
public virtual void OnEvent(Microsoft.SharePoint.SPListEvent listEvent)
{
WriteToFile("The event has been fired. Entered the custom event handler.");
WriteToFile("List Event dump:- " + listEvent.ToString());
if (listEvent == null)
{
throw new ArgumentNullException("listEvent", "list event object cannot be null");
}
WriteToFile("Getting the cached event sink.");
BaseEventSink sink = GetCachedEventSink(listEvent);
WriteToFile("Got the cached event sink.");
WindowsImpersonationContext wip = null;
//Ensure each sink instance handles only one event at a time.
lock(sink)
{
try
{
//Make sure the sink class has the current SPListEvent object
sink.EventInfo = listEvent;
//Impersonate the appropriate user
WriteToFile("Impersonating the administrator");
WindowsIdentity id = sink.HandlerIdentity;
if (id != null)
wip = id.Impersonate();
WriteToFile("Impersonation completed.");
WriteToFile("Now passing control to the event handler.");
sink.HandleEvent();
}
finally
{
//Cleanup
if (wip != null)
wip.Undo();
if (m_web != null)
m_web.Close();
//Null out cached SPWeb and SPList objects so that
//fresh ones are obtained for the next event.
m_web = null;
m_list = null;
}
}
}
/// <summary>
/// HandleEvent is called when an event occurs. Child classes should perform the main
/// event handling actions here.
/// </summary>
protected void HandleEvent()
{
WriteToFile("Entered the actual event handler.");
WriteToFile("The event is of type:- " + EventInfo.Type.ToString());
switch (EventInfo.Type)
{
case SPListEventType.Update:
case SPListEventType.Insert:
UpdateInsertHandler();
break;
}
}
/// <summary>
/// Used To restore files from Recycle Bin into the document library of origin
/// </summary>
private void UpdateInsertHandler()
{
WriteToFile("Entered the UpdateInserthandler.");
string fileLocation = EventInfo.UrlAfter;
WriteToFile("Got the file ___location:- " + fileLocation);
SPFile miscFile = EventWeb.GetFile(fileLocation);
// string newFileLoc = fileLocation.Remove(0, strRecycle.Length);
string newFileLoc = fileLocation.Remove(0, Configuration.RecycleBinLib.Length+1);
WriteToFile("Getting the new ___location:- " + newFileLoc);
try
{
// miscFile.MoveTo(string.Concat(strMain,"/",newFileLoc),true);
WriteToFile("Moving the file to the new ___location.");
miscFile.MoveTo(string.Concat(Configuration.MainLib,"/",newFileLoc),true);
WriteToFile("Move completed.");
}
catch(Exception ex)
{
PublishException(ex.ToString());
}
}//UpdateInsertHandler
/// <summary>
/// The SPListEvent object that describes the current event.
/// </summary>
protected virtual SPListEvent EventInfo
{
get
{
return m_ListEvent;
}
set
{
m_ListEvent = value;
m_web = null;
m_list = null;
m_fileUrl = null;
m_sinkData = null;
}
}
/// <summary>
/// The SPWeb object for the web site that contains the list
/// that the event occured on.
/// </summary>
protected virtual SPWeb EventWeb
{
get
{
if (m_web == null)
{
m_web = m_ListEvent.Site.OpenWeb();
}
return m_web;
}
}
/// <summary>
/// The SPList object for the list the event occured on.
/// </summary>
protected virtual SPList EventList
{
get
{
if (m_list == null)
{
m_list = EventWeb.Lists[EventInfo.ListID];
}
return m_list;
}
}
/// <summary>
/// The url of the file the event occured on.
/// Equals UrlAfter if UrlAfter is not empty. Otherwise equals
/// UrlBefore.
/// </summary>
protected string EventFileUrl
{
get
{
if (m_fileUrl == null)
{
string webUrl = m_ListEvent.WebUrl == null ? "<NULL>" : m_ListEvent.WebUrl;
string webRelUrl = m_ListEvent.UrlAfter;
if (webRelUrl == null || webRelUrl.Length == 0)
{
webRelUrl = (m_ListEvent.UrlBefore == null || m_ListEvent.UrlBefore.Length == 0 ?
"<NULL>" : m_ListEvent.UrlBefore);
}
m_fileUrl = String.Format("{0}/{1}", webUrl, webRelUrl);
}
return m_fileUrl;
}
}
protected string Data
{
get
{
if (m_sinkData == null)
{
m_sinkData = m_ListEvent.SinkData;
}
return m_sinkData;
}
}
# region Custom Code
/// <summary>
/// Converts XML string retrieved from SinkData property into an object
/// </summary>
protected EventSinkData Configuration
{
get
{
try
{
m_ConfigData = EventSinkData.GetInstance(Data);
return m_ConfigData;
}
catch(Exception ex)
{
PublishException(ex.ToString());
}
return null;
}
}//Configuration
/// <summary>
/// Makes sure that the proper folder structure is in place for copying, moving or inserting a file in to the mirror
/// document library or the Recycle Bin document library.
/// </summary>
/// <param name="web">
/// Web where the folder structure needs to be built or ensured
/// </param>
/// <param name="finalUrl">
/// Url containing the structure that needs to be built, must contain the trailing "/" if it is not a link to a file.
/// If it is a link to a file the file name will be stripped and the folder structure ensured.
/// </param>
/// <returns>
/// File path that has been built
/// </returns>
protected static string EnsureParentFolder(SPWeb web, string finalUrl)
{
finalUrl = web.GetFile(finalUrl).Url;
int x = finalUrl.LastIndexOf("/");
string epf = String.Empty;
if(x <= -1)
return epf;
epf = finalUrl.Substring(0, x);
SPFolder folder = web.GetFolder(epf);
if(folder.Exists)
return epf;
SPFolder curFolder = web.RootFolder;
string [] folders = epf.Split('/');
for(int i = 0; i < folders.Length; i ++)
{
curFolder = curFolder.SubFolders.Add(folders[i]);
}
return epf;
}//EnsureParentFolder
protected static void PublishException(string errors)
{
if(errors.Length > 0)
{
if(!EventLog.SourceExists(SOURCENAME))
EventLog.CreateEventSource(SOURCENAME, LOGNAME);
EventLog el = new EventLog();
el.Source = LOGNAME;
el.WriteEntry(errors, EventLogEntryType.Error);
}
}
# endregion
# region Windows Impersonation Code
/// <summary>
/// The WindowsIdentity class of the identity the Event Sink should impersonate.
/// </summary>
protected virtual WindowsIdentity HandlerIdentity
{
get
{
m_Identity = CreateIdentity(Configuration.UserName,
Configuration.Domain,
Configuration.Password);
return m_Identity;
}
}
/// <summary>
/// Helper method to handle creating a WindowsIdentity object from a username / ___domain / password.
/// </summary>
/// <param name="User">The username of the account to impersonate.</param>
/// <param name="Domain">The ___domain of the account to impersonate.</param>
/// <param name="Password">The password of the account to impersonate.</param>
/// <returns></returns>
public static WindowsIdentity CreateIdentity(string User, string Domain, string Password)
{
// The Windows NT user token.
IntPtr tokenHandle = new IntPtr(0);
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_NETWORK_CLEARTEXT = 3;
tokenHandle = IntPtr.Zero;
// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(User, Domain, Password,
LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);
if (false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
throw new Exception("LogonUser failed with error code: " + ret);
}
//The WindowsIdentity class makes a new copy of the token.
//It also handles calling CloseHandle for the copy.
WindowsIdentity id = new WindowsIdentity(tokenHandle);
CloseHandle(tokenHandle);
return id;
}
# endregion
/// <summary>
/// Get the cached event sink object to handle this event.
/// </summary>
/// <returns>The cached IListEventSink object that should handle the current event.</returns>
private BaseEventSink GetCachedEventSink(SPListEvent evt)
{
BaseEventSink sink = null;
//Syncrhonize both reads and writes to the cache.
//Even though the Hashtable class is threadsafe for reads, we don't want to have
//multiple sink instances per list. Otherwise, if many events occur on a list
//right off the bat, you could get many instances that all have to initialize
//themselves.
lock(SinkCache.SyncRoot)
{
sink = SinkCache[evt.ListID] as BaseEventSink;
//The cached sink is only fit if it is the same type and has the same data
//as the current sink.
if (sink == null ||
! sink.GetType().Equals(this.GetType()) ||
evt.SinkData != sink.Data)
{
//Update the cache, throw away the old sink if it exists.
SinkCache[evt.ListID] = this;
sink = this;
}
}
return sink;
}
# region Win32 API calls
[DllImport("advapi32.dll", SetLastError=true)]
private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private extern static bool CloseHandle(IntPtr handle);
# endregion
protected SPListEvent m_ListEvent;
private SPWeb m_web;
private SPList m_list;
private string m_fileUrl;
private string m_sinkData;
// Custom variables start
private EventSinkData m_ConfigData;
protected static Hashtable SinkCache = new Hashtable();
private const string SOURCENAME = "Recycle Bin";
private const string LOGNAME = "Recyclebin.EventSink";
// private string strMain = "TEST";
// private string strRecycle = "Recycle Bin";
private WindowsIdentity m_Identity = null;
// Custom variables end
// Logging
private static void WriteToFile(String input)
{
try
{
string filePath=@"C:\sharepoint\Log.txt";
FileInfo logFile = new FileInfo(filePath);
if(logFile.Exists)
{
if (logFile.Length >= 100000)
File.Delete(filePath);
}
FileStream fs = new FileStream(filePath,FileMode.OpenOrCreate, FileAccess.ReadWrite);
StreamWriter w = new StreamWriter(fs);
w.BaseStream.Seek(0,SeekOrigin.End);
w.WriteLine(input);
w.WriteLine("--------------------------------------------------------------");
w.Flush();
w.Close();
}
catch(System.Exception ex)
{
PublishException(ex.ToString());
}
}
}
}