Added support for SSL, Ldap Events, Edir Events
[mono.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap.Events / PSearchEventSource.cs
1 /******************************************************************************
2 * The MIT License
3 * Copyright (c) 2003 Novell Inc.  www.novell.com
4
5 * Permission is hereby granted, free of charge, to any person obtaining  a copy
6 * of this software and associated documentation files (the Software), to deal
7 * in the Software without restriction, including  without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
9 * copies of the Software, and to  permit persons to whom the Software is 
10 * furnished to do so, subject to the following conditions:
11
12 * The above copyright notice and this permission notice shall be included in 
13 * all copies or substantial portions of the Software.
14
15 * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *******************************************************************************/
23 //
24 // Novell.Directory.Ldap.Events.PSearchEventSource.cs
25 //
26 // Author:
27 //   Anil Bhatia (banil@novell.com)
28 //
29 // (C) 2003 Novell, Inc (http://www.novell.com)
30 //
31
32
33 using System;
34 using Novell.Directory.Ldap.Controls;
35
36 namespace Novell.Directory.Ldap.Events
37 {
38   /// <summary> 
39   /// This is the source class for Ldap events.
40   /// </summary>
41   public class PSearchEventSource : LdapEventSource
42   {
43     protected SearchResultEventHandler search_result_event;
44
45     /// <summary> 
46     /// Caller has to register with this event in order to be notified of
47     /// corresponding Ldap search result event.
48     /// </summary>
49     public event SearchResultEventHandler SearchResultEvent
50     {
51       add
52       {
53         search_result_event += value;
54         ListenerAdded();
55       }
56       remove
57       {
58         search_result_event -= value;
59         ListenerRemoved();
60       }
61     }
62
63     protected SearchReferralEventHandler search_referral_event;
64
65     /// <summary>
66     /// Caller has to register with this event in order to be notified of
67     /// corresponding Ldap search reference event.
68     /// </summary>
69     public event SearchReferralEventHandler SearchReferralEvent
70     {
71       add
72       {
73         search_referral_event += value;
74         ListenerAdded();
75       }
76       remove
77       {
78         search_referral_event -= value;
79         ListenerRemoved();
80       }
81     }
82
83     /// <summary> 
84     /// SearchResultEventHandler is the delegate definition for SearchResultEvent.
85     /// The client (listener) has to register using this delegate in order to
86     /// get corresponding Ldap events.
87     /// </summary>
88     public delegate 
89     void SearchResultEventHandler(
90                                   object source,
91                                   SearchResultEventArgs objArgs
92                                   );
93
94     /// <summary> 
95     /// SearchReferralEventHandler is the delegate definition for SearchReferralEvent.
96     /// The client (listener) has to register using this delegate in order to
97     /// get corresponding Ldap events.
98     /// </summary>
99     public delegate 
100     void SearchReferralEventHandler(
101                                     object source,
102                                     SearchReferralEventArgs objArgs
103                                     );
104
105     protected override int GetListeners()
106     {
107       int nListeners = 0;
108       if (null != search_result_event)
109         nListeners = search_result_event.GetInvocationList().Length;
110
111       if (null != search_referral_event)
112         nListeners += search_referral_event.GetInvocationList().Length;
113
114       return nListeners;
115     }
116
117     protected LdapConnection mConnection;
118     protected string mSearchBase;
119     protected int mScope;
120     protected string[] mAttrs;
121     protected string mFilter;
122     protected bool mTypesOnly;
123     protected LdapSearchConstraints mSearchConstraints;
124     protected LdapEventType mEventChangeType;
125
126     protected LdapSearchQueue mQueue;
127
128     // Constructor
129     public PSearchEventSource(
130                               LdapConnection conn,
131                               string searchBase,
132                               int scope,
133                               string filter,
134                               string[] attrs,
135                               bool typesOnly,
136                               LdapSearchConstraints constraints,
137                               LdapEventType eventchangetype,
138                               bool changeonly
139                               )
140     {
141       // validate the input arguments
142       if ((conn == null)
143           || (searchBase == null)
144           || (filter == null)
145           || (attrs == null)) 
146       {
147         throw new ArgumentException("Null argument specified");
148       }
149       
150       mConnection = conn;
151       mSearchBase = searchBase;
152       mScope = scope;
153       mFilter = filter;
154       mAttrs = attrs;
155       mTypesOnly = typesOnly;
156       mEventChangeType = eventchangetype;
157
158       // make things ready for starting a search operation
159       if (constraints == null) 
160       {
161         mSearchConstraints = new LdapSearchConstraints();
162       } 
163       else 
164       {
165         mSearchConstraints = constraints;
166       }
167       
168       //Create the persistent search control
169       LdapPersistSearchControl psCtrl =
170         new LdapPersistSearchControl((int)eventchangetype,// any change
171                                      changeonly, //only get changes
172                                      true, //return entry change controls
173                                      true); //control is critcal
174
175       // add the persistent search control to the search constraints
176       mSearchConstraints.setControls(psCtrl);
177     } // end of Constructor
178
179     protected override void StartSearchAndPolling()
180     {
181       // perform the search with no attributes returned
182       mQueue =
183         mConnection.Search(mSearchBase, // container to search
184                     mScope, // search container's subtree
185                     mFilter, // search filter, all objects
186                     mAttrs, // don't return attributes
187                     mTypesOnly, // return attrs and values or attrs only.
188                     null, // use default search queue
189                     mSearchConstraints); // use default search constraints
190
191       int[] ids = mQueue.MessageIDs;
192
193       if (ids.Length != 1)
194       {
195         throw new LdapException(
196                                 null,
197                                 LdapException.LOCAL_ERROR,
198                                 "Unable to Obtain Message Id"
199                                 );
200       }
201
202       StartEventPolling(mQueue, mConnection, ids[0]);
203     }
204
205     protected override void StopSearchAndPolling()
206     {
207       mConnection.Abandon(mQueue);
208       StopEventPolling();
209     }
210
211     protected override bool NotifyEventListeners(LdapMessage sourceMessage,
212                                EventClassifiers aClassification,
213                                int nType)
214     {
215       bool bListenersNotified = false;
216       if (null == sourceMessage)
217       {
218         return bListenersNotified;
219       }
220
221       switch (sourceMessage.Type)
222       {
223       case LdapMessage.SEARCH_RESULT_REFERENCE :
224         if (null != search_referral_event)
225         {
226           search_referral_event(this,
227                                 new SearchReferralEventArgs(
228                                                         sourceMessage,
229                                                         aClassification,
230                                                         (LdapEventType)nType)
231                                 );
232           bListenersNotified = true;
233         }
234         break;
235
236       case LdapMessage.SEARCH_RESPONSE:
237         if (null != search_result_event)
238         {
239           LdapEventType changeType = LdapEventType.TYPE_UNKNOWN;
240           LdapControl[] controls = sourceMessage.Controls;
241           foreach(LdapControl control in controls)
242           {
243             if (control is LdapEntryChangeControl)
244             {
245               changeType = (LdapEventType)(((LdapEntryChangeControl)control).ChangeType);
246               // TODO: Why is this continue here..? (from Java code..)
247               // TODO: Why are we interested only in the last changeType..?
248               continue;
249             }
250           }
251           // if no changeType then value is TYPE_UNKNOWN
252           search_result_event(this, 
253                               new SearchResultEventArgs(
254                                                         sourceMessage, 
255                                                         aClassification, 
256                                                         changeType)
257                               );
258           bListenersNotified = true;
259         }
260         break;
261
262       case LdapMessage.SEARCH_RESULT:
263         // This is a generic LDAP Event
264         // TODO: Why the type is ANY...? (java code)
265         NotifyDirectoryListeners(new LdapEventArgs(sourceMessage, 
266                                                    EventClassifiers.CLASSIFICATION_LDAP_PSEARCH, 
267                                                    LdapEventType.LDAP_PSEARCH_ANY));
268         bListenersNotified = true;
269         break;
270
271       default:
272         // This seems to be some unknown event.
273         // Let this be notified to generic DirectoryListeners in the base class...
274         break;
275       }
276
277       return bListenersNotified;
278     }
279   } // end of class PSearchEventSource
280 }