Lotus notes impersonation - access email/calendar of another person - c#

I'm searching for a way to access the calendar and email inbox of another user (I can access my own calendar/email without any problems). Currently I can access the other inbox/calendar via lotus notes (I have enough rights). But I couldn't manage it to access the data programmatically.
I already listed all my views, but there was nothing appropriated.
private Domino.NotesDatabase db;
Object[] docColl = this.db.Views as Object[];
foreach (Object objView in docColl)
{
NotesView view = objView as NotesView;
this.WriteToLog(view.Name);
}
Any ideas, if this is possible and how?

Every Notes user's mail box is in a separate database.
So, first you have to get the database with
Domino.NotesDatabase db =
session.GetDatabase("yourServer", "UserMail.nsf", false);
and there you can access the calendar and email folders.

#Knut's answer gives you the basic information that you need, but I'd like to clarify it a bit: it has to be the hisServer (or herServer), not yourServer. Also, it will usually be "mail\hisShortname.nsf"), but that's not always the case. The point is that if you are trying to write generalized code, you have to look these things up in the Domino Directory.
If you're using a recent version of the Notes APIs, the best way to proceed is by using session.getDirectory(myServer) to get a NotesDirectory object. (It doesn't matter what server you use in this case, as long as the users are in the same Notes domain.) Here's the doc for the getDirectory method.
Once you have a handle to the Domino Directory, you need to look up information for the Person whose mail file you want to access. The formal documentation for the NotesDirectory class seems to be frustratingly hard to find online every time I search for it, so I can't link to that. The second example in the first section of this wiki page shows a call to the LookupNames method to retrieve information for a Person object, which is what you need to do. The two items that you want to retrieve are "MailServer" and "MailFile".

Related

How to open the Property dialog of selected objects in Management Console?

I am searching for the possibility to open default property dialogues for particular Windows objects, like:
the property dialogue for a particular service in services.msc
the property dialogue for a particular scheduled taks in taskschd.msc
etc.
I do not want to interact with that dialogues or change any of the properties. I just want to open them to give the user direct access to a single items properties (instead of opening the listings (by calling the *.msc executables) in which the user has to search the object again).
I have already partially copied the dialogues functions into own forms and code for other purposes, by the way, but I want to give the user the option to open the default ones and make any changes directly.
Now, I have found some hints but I am stuck as there is always some crucial information missing:
1. Using so-called SnapIns of MMC (Microsoft Management Console)
There is this relatively new answer which uses VB code but I have no clue how I could use the MMC Automation Object Model in C# .NET Framework.
Furthermore, there is no clean and easy example/explanation of how to simply call an existing .msc process/list/window by usage of the Microsoft.ManagementConsole. Instead, there are several horrifying complex tutorials how to implement SnapIns into C#.
To be clear here: What I want to do is to reference a dll, go through some list (if necessary) and just call the properties dialogue.
2. COM invoke of old API
There is this old answer where someone recommends using invoke on an outdated ITaskScheduler class which does not solve the general dialogue call but at least the one for scheduled tasks. Perhaps it is also possible to use something similar for services, etc. - but, again, there is no clear example or explanation of how to implement this approach.
It's relatively simple.
Add a COM Reference to Microsoft Management Console 2.0.
Add the using MMC20 directive.
Create a new MMC20.Application object
Use the Application.Load() method to load a Snap-In (services.msc here)
The ActiveView of the Application Document contains the list of items: ListItems Property
Select a Node by name or Index and call the DisplaySelectionPropertySheet() method to show its Property pane
For example:
Note: setting mmcApp.UserControl = 1; leaves the Console open, otherwise it would close.
using MMC20;
// [...]
MMC20.Application mmcApp = new MMC20.Application();
mmcApp.UserControl = 1;
mmcApp.Load("services.msc");
var doc = mmcApp.Document;
var view = doc.ActiveView;
var node = view.ListItems.OfType<Node>().FirstOrDefault(n => n.Name == "Base Filtering Engine");
if (node != null) {
view.Select(node);
view.DisplaySelectionPropertySheet();
}
To enumerate the ListItems, use a standard loop or an extension method as shown above:
var nodes = view.ListItems;
foreach (MMC20.Node node in nodes) {
Console.WriteLine(node.Name);
}
Here's documentation on how to use the MMC SDK. It's a Win32 API, so you'll have to use COM, PInvoke, or other interop to use it.
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/mmc/microsoft-management-console-start-page#developer-audience
The C++ examples are probably more informative than the VB ones. The .h files are part of the windows sdk so you should be able to find the clsid and other constants that you need in there: https://learn.microsoft.com/en-us/previous-versions/windows/desktop/mmc/using-c-with-the-mmc-2-0-automation-object-model

C# Outlook Add-in: How can I delete a User-defined property programmatically?

I have tried finding an answer to this question practically everywhere I could imagine, including here on StackOverflow. Unfortunately to no avail. So here it is.
I'm working on an Outlook Add-in (with Outlook 2021), and have developed some code that creates some ItemProperties specifically for use with that add-in. Now, when those properties are created, I can see them when I go to View->Settings->Advanced View Settings->Columns, as illustrated in the screenshot.
Screenshot of User-defined fields in Outlook
In some cases, though, I want to completely delete the properties. And as I know how to do that manually, as pointed out in the figure, I can't find out how to do that programmatically via C#. I have gone that far as to remove the properties from each mail containing that kind of property, like this:
IEnumerable<MailItem> listOfAssignedEmails = itemsToProcess.Where(
t => t.ItemProperties[MailExpiration.ExpirationDatePropertyName] != null);
foreach (MailItem email in listOfAssignedEmails)
{
// Note: The Delete() operation is deprecated. A more up-to-date method must be found.
email.ItemProperties[MailExpiration.ExpirationDatePropertyName].Delete();
email.Save();
}
... and yes, I know that the Delete() operation is deprecated; however, I couldn't find another method for removing the ItemProperty from the email (any suggestions are welcome).
Basically, the deletion of this Property is only going to be done very rarely (t. ex. if the user chooses to uninstall the Add-in. However, if there's any way to remove that property automatically, I would be happy to know.
Any suggestions will be greatly appreciated.
It is really a bad idea to remove a custom property from all emails that already have it: there is really no point since the user will never see them, but you will have to retouch (and thus change the last modified date) of a large number of emails.
Also note that named properties in MAPI are a finite resource - you can have at most 64k of them in a mailbox. Once a particular property mapping is used, you can never unmap it, even if there are no items that use that property.
Thirdly, doing anything Outlook related from an installer (rather than a VSTO addin) is a really bad idea - Windows installer runs in a service.
If you want to make sure the user no longer sees your custom fields as available properties in a view, you need to deal with the folder fields - they ar stored in a blob in a hidden (associated) message in that folder. OOM does not expose folder fields at all (if you don't count the AddToFolderFields parameter when calling UserProperties.Add). If using Redemption is an option (I am its author), it exposed RDOFolderFields object (accessible from RDOFolder2.FolderFields property) that allows to add or delete folder fields.
The list of properties shown on the screenshot belongs to the Folder.UserDefinedProperties property which returns a UserDefinedProperties object that represents the user-defined custom properties for the Folder object.
Use the ItemProperties.Remove method removes an object from the collection (from an item).
Use the ItemProperties property to return the ItemProperties collection. Use ItemProperties.Item(index), where index is the name of the object or the numeric position of the item within the collection, to return a single ItemProperty object.

c# static Data Dictionary lingering when source data changes - even across IIS users

I have an online store and the software is highly customized but not completely ours. We sell tours and some of them have reservations so I added a calendar to let them pick the date/time they want. Originally each cal_SelectionChanged() call was looking stuff up from the store database and that was, of course, horribly slow. I wanted to use a Data Dictionary to get the information once and use it whenever needed.
I have this class:
public partial class ConLib_Custom_BuyTourProductDialog : System.Web.UI.UserControl
and this declared inside that class.
static Dictionary<string, string> CustomFieldDict = new Dictionary<string, string>();
I also have a function to load all the bits from a database that I'll need on my page. My plan was to call this on Page_Load() and just access the info when needed.
protected void LoadCustomFieldDictionary()
{
string _sku = _Product.Sku.Trim().ToLower();
if (CustomFieldDict.ContainsKey("Sku"))
{
// is the dictionary entry for *this* sku?
if (CustomFieldDict["Sku"] == _sku)
{
return; // already have this one.
}
}
CustomFieldDict["Sku"] = _sku;
CustomFieldDict["EventId"] = TTAUtils.GetCustomFieldValue(_Product, "EventId");
CustomFieldDict["ResEventTypeId"] = TTAUtils.GetCustomFieldValue(_Product, "ResEventTypeId");
etc.
}
Then my boss loaded a page - ok, everything was fine - and changed one of the bits of data in the database to point to a different, wrong, ResEventTypeId. Reload the page and it has the new data. He changed it back to the original and it was "stuck" on the wrong information. I loaded a browser on my iPad and went there and it fed me the wrong info as well.
It seems that the server is caching that DataDictionary and even if we change the database all visitors, even in other sessions, get this cached wrong info.
Do you think this assessment is right?
What's the proper way to do this so that a visitor changing dates gets some kind of cached lookup speed and yet another browser gets a fresh set from the database?
How do I make it "forget" what it thinks it knows and accept the new info until I fix it? Reset IIS?
Thankfully this is on a dev server and not my live store!
Thanks for your help. I've learned a lot about C# and .NET but it's shade-tree-mechanic type stuff and I lack the formal training that is out there and would really help in situations like these. Any help is appreciated!
For anyone coming by at a later time:
What Jonesy said is very true - statics are scary. I found out from one site (link to a link from his link) that statics like this are sticky to the Application Pool level so any other browser would get the "wrong" information.
For my situation I decided to use ViewState to store the info since it was small and my current V.S. isn't very large already. Beware doing this for large amounts of data but in my case it was the best.

Data Access Library: What to return if access isn't allowed or data isn't found?

I'm building a DAL for a widget-based reporting application, its been designed in such a way that users pick, configure and deploy reporting 'widgets' to their home screens. Widgets can report across various kinds of company data - sites, brands, employees and so on.
Whilst all users can access all the widgets/reports, all users are not authorised to access all data. If I work for Company-A I can't view sales reports for Company-B or staff attendance data for a salesman at Company-C, however I can configure such a report and add it to my 'dashboard'.
At runtime, an intermediate 'DataService' class has the job of checking the user's credentials and, if access is permitted, returning the appropriate object collection to the client.
On the initial build I just returned an empty List if access to the data was not allowed, but this is also what I do if no data is returned by the report (which can happen). I'd like to show an 'Access Denied' message on the front end if the user isn't authorised to view the data but obviously if all I get back in either eventuality is an empty collection its impossible to know if this was because of insufficients rights or just no data.
I'd be grateful if you could suggest a way of coding around this, my first thought was to move the credential-checking into another object which in turn calls the data access class but time constraints mean this isn't an option.
The only thing I can think of, which goes against everything I've ever learnt, is to throw a custom exception e.g. InsufficientApplicationPrivilegeException if access isn't granted, but this smells bad.
Thanks for reading.
I think you have a couple of options. One is to make a composite object that your data service class returns. The composite object looks something like this: -
class DataResult<T>
{
IEnumerable<T> Data;
Result ServiceResult;
}
ServiceResult contains metadata about the outcome of your service call - it could be an enum which contains e.g. Success, AuthenticationFailure etc. etc.. You can then switch on this in order to do different behaviour.
An alternative option might be to use the NullObject pattern that shows a single item of data in the view which instead of real data simply shows "Access Denied" for the display properties of the object. The advantage of this approach is that your front-end doesn't need to have any conditional logic etc.; however if you want to show a specific message box or similar rather than just displaying a dummy row of data in your widget, then this probably isn't appropriate.

What is the most DRY way to get data out of my database?

I have to write an ASP.NET application that connects to our legacy IBM Universe Database and we are using a product called mv.net which allows us to connect, read, write, select, run server side programs, etc.
I want as little code repetition as possible but I also want as little data transfer as possible as well.
In order to open a connection we must first get a reference to the account using code such as:
mvAccount myAccount = new mvAccount(serverName, login);
Then we can read an item:
mvFile myInvoiceFile = myAccount.FileOpen("INVOICE");
mvItem myInvoiceRecord = myInvoiceFile.Read(invoiceID);
Then we we're done:
myAccount.Logout();
I have a Class for each module, so I may have INVOICE, PURCHASE_ORDER, RMA, REQ, SHIPMENT, and so on. Within INVOICE, I may need to access multiple tables such as CUSTOMER, INVOICE, TERMS, SHIPVIA, etc.
What I planned to do was create a class called TechDB which is the name of our database and put the code in there so in my INVOICE class I can just say:
TechDB connection = new TechDB();
mvItem myInvoiceRecord = connection.Read("INVOICE", invoiceID)
When I do this my TechDB class would open the connection, read the record, and then logout all in one step.
I think I'm heading down the right path but please let me know if not. Here are my problems with this:
How do I return errors my INVOICE class? For example, errors could occur if we are unable to connect to the database, unable to open the file, unable to read the record.
What if I then need to take some data from my INVOICE and then read the TERMS table. I'd hate to have to open a new connection to the database when I just opened one.
Should I call the Dispose method on all classes that have this? For example, the mvAccount has a Dispose method. None of the documentation says to call it, but should I after the Logout()?
Could I create a Dispose method on the TechDB class that does the myAccount.Logout()? That way the connection would remain open and I could close it from my INVOICE class when I was completely done with it?
Give me some opinions on the best way to handle this? My goal is a robust application that is easy to modify and as little code repitition as possible.
I would use closures, I think for C# you have Delegates. So something like:
MyAccount.loginAndDo(servername, login, delegate(account){
invoice = account.read("INVOICE");
.
.
.
});
In loginAndDo, you would login, call the delegate, and then close the account.
Custom exception classes
One idea would be to construct batch requests, (a list of delegates).
as per 3/4. In my case, all of my data access objects inherit from a class that holds a static reference to a connection. I'm hesitant to implement disconnect logic in Dispose because of the possibility that there is a power out or system crash or something and that connection isn't released.

Categories

Resources