Welcome to Technolog Sign in | Join | Help

May 2006 - Posts

The C# sample at the IPN website, is a little bit outdated, since paypal currently supports international  character sets (great!) so if a chinese customer would enter his name in Chinese for instance :), it still would be kept ok. So to not corrupt the characters, we have to stick the same format as paypal sends us. This would be simple if the page would be a web service form, it is not, so we have to wrap the POST request and do the encoding all yourselves.

using System;

using System.Collections;

using System.Collections.Specialized;

using System.IO;

using System.Text;

using System.Net;

using System.ComponentModel;

using System.Data;

using System.Web;

 

using CSession;

namespace pp

{

      /// <summary>

      /// Summary description for ipn.

      /// </summary>

      public partial class ipn : System.Web.UI.Page

      {

            private bool isTesting;

            // this page runs as LCID 1033 english

            // and is tested on codepage 65001. you must –enable- the codepage

            // on your paypal preferences!

            // note that the shopping basket, is based on ISP Session from

            // http://www.nieropwebconsult.nl/asp_session_manager.htm

            // it integrates with classic asp as well as .NET

            protected void Page_Load(object sender, System.EventArgs e)

            {

                 

                  NameValueCollection rq = Request.Form;

                  //Response.BufferOutput = false;

                  string test_ipn = rq["test_ipn"];

                  isTesting = test_ipn != null && test_ipn == "1"? true: false;

                  // Create the request back

// instead of pp_url you could read https://www.paypal.com/cgi-bin/webscr

                  HttpWebRequest req = (HttpWebRequest) WebRequest.Create(

      System.Configuration.ConfigurationSettings.AppSettings["pp_url"]);

           

                  string version = rq["notify_version"]; // ' 2.1 currently

                  // Set values for the request back

                  req.Method = "POST";

                  string notifyCmd = "cmd=_notify-validate";

                  req.ContentType = "application/x-www-form-urlencoded";     

            // the charset will be utf-8 if set as preference on paypal!

            Encoding enc = System.Text.Encoding.GetEncoding(rq["charset"]);

           

            StreamWriter tw = new StreamWriter(new MemoryStream());

            int keyCount = rq.Count;

            // here goes our first command

            tw.Write(notifyCmd);

            //tricky part. If you do Request.Form.ToString() the & and the = is encoded as well!

            for (int xx = 0; xx < keyCount; xx++)

            {  

                tw.Write('&');

                tw.Write(HttpUtility.UrlEncodeToBytes(rq.GetKey(xx), enc));

                tw.Write('=');

                tw.Write(HttpUtility.UrlEncodeToBytes(rq.Get(xx), enc));

            }

           

            int contLen = (int)tw.BaseStream.Position;

            req.ContentLength = contLen;

            // Write the request back IPN strings in binary form

            // do not use a TextWriter since that would cause

            // encoding on encoding which obviously will fail

            byte[] temp = new byte[contLen];

            tw.BaseStream.Position = 0;

            tw.BaseStream.Read(temp, 0, contLen);

            Stream stOut = req.GetRequestStream();

            stOut.Write(temp, 0, contLen);

            stOut.Flush();           

 

            // Do the request to PayPal and get the response

            StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream(), enc);

                  string strResponse = stIn.ReadToEnd();

                  stIn.Close();

                  string Item_number, Payment_status, Txn_id, sessionId;

                  Item_number = rq["item_number"];

                  sessionId = rq["invoice"];

                  Txn_id = rq["txn_id"];

                 

                  db dbl = new db();

                  dbl.sqlConn.Open();

                 

                  DataSet1.tLicenseRow lic =  dbl.dataSet11.tLicense.NewtLicenseRow();

                  lic.CtryISO2Code = rq["address_country_code"];

                  lic.email = rq["payer_email"];

                  //TODO: lic should be fullfilled

                  lic.sessionID = new Guid(sessionId).ToByteArray();

                  lic.transactionID = Guid.NewGuid();

            lic.salesBlob = rq.ToString().Replace("&", "\r\n");

                  lic.saleDate = DateTime.Now;

                  lic.total_value = decimal.Parse(rq["mc_gross"]);

                  lic.tax_value = decimal.Parse(rq["tax"]);

                  lic.salesBlobType = 1;

                  lic.total_fee = decimal.Parse(rq["mc_fee"]);

                  Payment_status = rq["payment_status"];

                  lic.Payment_status = Payment_status;

                  lic.downloadComplete = 0;

                  // Create the IpnTransaction

                  basket bsk = null;

 

                  bool validSession = false;

                  if (sessionId != null && sessionId.Length == 32)

                  {    

                        bsk = new basket(sessionId);

                        validSession = true;

                  }

                  // Confirm whether the IPN was VERIFIED or INVALID. If INVALID, just ignore the IPN

                  if (strResponse == "VERIFIED")

                  {

                        if (validSession)

                        {

                              bsk.Session["Payment_status"] = 1;

                              bsk.setPurchaseAuthorized(lic.transactionID);

                              msg.Text = "valid";

                              Response.AppendToLog("valid session");                           

                        }

                        else

                        {

                              Response.AppendToLog("invalid session");

                    msg.Text = "invalid";

                        }

              

                  }

                  else

                  {

                        if (validSession)

                        {

                              Response.AppendToLog("invalid transaction, valid session");

                              msg.Text = "invalid";

                              bsk.Session["payment_status"] = 0;

                        }                      

                  }

            dbl.dataSet11.tLicense.AddtLicenseRow(lic);

            dbl.tLicense.Update(dbl.dataSet11.tLicense);

                  dbl.sqlConn.Close();

                  dbl.Dispose();

                  if (bsk != null) bsk.Dispose();

 

            }

 

 

      }

}

 

If you have to deal with MIME you'll have to interpret date information.

Some programmers argue, that the DotNet framework, should support the RFc822 date format out of the box.
Others say,  'no, you need not, because RFC1123  has already been implemented which goes as "Sun, 04 Dec 2005 20:57:57 GMT" for instance'.

I do not agree with this completely. First because sometimes, you might want to be able to detect the timezone difference between clients. If you have a GMT notation, you have the correct worldtime in sync, but you won't see a difference.

Second, if the RFC or API recommends a RFC822 it is a error to assume that the runtime or their runtime, automatically will deal with rfc1123 as well (it is in many situations).

So here is a way to format your string into rfc822. I did not pack it into a handy class or something. Just use the idea. You could make it detect and accept rfc822 and rfc1123 as well!

    // the (UTC) suffix  is optional. You can leave it out.

    DateTime dt = DateTime.Now;

    string Rfc822DateTime = dt.ToString(@"ddd, dd MMM yyyy HH:mm:ss zzzz (\U\T\C)", System.Globalization.DateTimeFormatInfo.InvariantInfo);

    // remove the time separator in the timezone because zzzz will produce +01:00 for instance

    Rfc822DateTime = Rfc822DateTime.Remove(Rfc822DateTime.LastIndexOf(':'), 1);

 

    // for the sake of completeness I want to state that formatting as an RFc1123 string is as simple as formatting using a predefined mask that is .ToString("r").

    // and do not forget the ToUniversalTime() method or otherwise, the time string is still a local time!

    string rfc1123DateTime = dt.ToUniversalTime().ToString("r"); 

 

    // and convert the rfc822 formatted date back 

    if (Rfc822DateTime.EndsWith("(UTC)"))

        Rfc822DateTime = Rfc822DateTime.Substring(0, Rfc822DateTime.Length - 6);

 

    DateTime rfc822Parse = DateTime.ParseExact(Rfc822DateTime, @"ddd, dd MMM yyyy HH:mm:ss zzzz", System.Globalization.DateTimeFormatInfo.InvariantInfo);

    // rfc822Parse equals e.g.: "Mon, 15 May 2006 08:31:40 GMT"

    // rfc1123DateTime equals eg.: "Mon, 15 May 2006 10:31:40 +0200"

   

    // converting from string to datetime also requires us to convert from UTC to Local manually

    DateTime rfc1123Parse = DateTime.ParseExact(rfc1123DateTime, "r", System.Globalization.DateTimeFormatInfo.InvariantInfo).ToLocalTime();

    if (rfc822Parse != rfc1123Parse)

        throw new FormatException("rfc822Parse and rfc1123Parse should be equal!");

Wouldn't it be fun to create new active directory objects, while you even don't startup the MMC for active directory? No, don't be afraid that everybody including ‘nobody’ on your network -now- can do this

If the code below does not run on a domain controller, you first should install the adminpak.msi (or register dsadmin.dll and dsa.mcs) for on Windows 2003 that also can be installed on Windows XP.

And of course, Active Directory is -really- secure. If the calling code is not executed by someone with sufficient rights, it will fail.

So here we go and make yourself really -see- active directory!

(ps: I like writing unique code, as far as I can see, nobody did it yet, hey, don't forget to visit www.adccure.nl !)

static void Main()

{

IDsAdminCreateObject co = new DsAdminCreateObject() as IDsAdminCreateObject;
object nativedsObject = new DirectoryEntry("LDAP://cn=users,dc=yourdomain,dc=local").NativeObject;
co.Initialize(nativedsObject, null, "user");
object newObject = co.CreateModal(DsAdminCreateObject.GetDeskTopWindow());

}

[ComImport, Guid("53554A38-F902-11d2-82B9-00C04F68928B"),

InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

public interface IDsAdminCreateObject

{

/// <summary>
///
Need to initialize before popping up the new object wizard
/// </summary>
///
<param name="ADsContainerObj">initialized dir object Container object eg: cn=users,DC=domain,dc=local</param>
///
<param name="ADsCopySource">can be null, specifies original object if you want a copy!</param>

/// <param name="ClassName">contains "User", "group", "contact", "inetOrgPerson" etc</param>
void Initialize( [MarshalAs(UnmanagedType.IDispatch)] object ADsContainerObj,
[MarshalAs(UnmanagedType.IDispatch), Optional(), DefaultParameterValue(null)] object ADsCopySource,
[MarshalAs(UnmanagedType.LPWStr)] string ClassName);

/// <summary>
///
Returns native ActiveDirectory object
/// </summary>
///
<param name="hwndParent">handle to parent window, specify 0 (mostly)</param>
[return: MarshalAs(UnmanagedType.IDispatch)]
object CreateModal(IntPtr hwndParent);

}

 

/// <summary>

/// Have our CLSID_DsAdminCreateObject be imported by .NET
/// </summary>
[ComImport, Guid("E301A009-F901-11d2-82B9-00C04F68928B")]
public class DsAdminCreateObject

{

/// we just needed a pointer to a window, if you run this code within a Windows Form, you can fetch a handle to it and hand it over to CreateModal!
[DllImport("user32", EntryPoint = "GetDesktopWindow", ExactSpelling = true, SetLastError = false)]
public static extern IntPtr GetDeskTopWindow();
}