Monday, September 01, 2008
Check out this blog article about a home purchase in the West Palm Beach area which could have been avoided if the home inspection was done professionally.
The blog article may be read at Bad Home Inspections.
The inspection was done July 1 2008, by Feldman Building Inspections Inc., located in Delray Beach, FL. If you think you can rely on an inspection to tell you everything about the property you’re about to purchase you are very much mistaken.
Friday, August 29, 2008
If you want to sell something on your website, perhaps something like a personalized kid's storybook, you can add a PayPal buy-button that will send the user to PayPal to make a payment to your PayPal account. You will get an email and then you can create and send the book to the buyer.
The Html code that makes up the button (created manually or from the PayPal button factory) contains things like your PayPal account email, the item description and price and perhaps a few other parameters. However, someone knowledgeable could view the source of your page or save the Html from the browser, change the price and then click the modified button and you will receive the order with a lower payment. Maybe you will notice it but if you get lots of orders for various items, it may go unnoticed until after you send the book.
The solution is to use PayPal's Encrypted Website Payments (EWP) buttons. This can be done by the button factory and you can set a flag in the profile to only allow encrypted buttons to be used on your site. People will no longer be able to modify your buttons in any way. All the parameters that make up the button are encrypted into one string of characters and that string is sent as a single parameter to PayPal when the button is clicked. When created by the factory, PayPal knows how to decrypt what it encrypted in the first place.
However, what if you want to dynamically generate your buy-buttons in your code? You can create the parameters as you need on the fly and use them unencrypted but if you want to encrypt them, you can't use the factory. For example, the personalized book's item description could be "Billy Jones and the Magic Pancake" which will display when the buyer enters PayPal to pay. Dynamic buttons are also useful when you have a database with lots of items. Once you create the set of parameters for the button, you can then run the string through an encryption routine and use the encrypted string in your buy button. The PayPal site explains how to do this (link).
There are several steps to do this as discussed in the link above:
- Obtain a private key and public certificate - You use your private key to decrypt something encrypted by your public cert. Public certs are used for encryption and authentication.
- Upload your public cert to PayPal - You then give away your public certificate to anyone that needs to authenticate that you are you or encrypt data to send to you. In this case, you upload your public cert to PayPal. Actually, PayPal does not need to send you anything encrypted so they mainly need your public cert for authentication. There are other non-PayPal uses of this private key/public cert pair like encrypted email but I will discuss that in a future posting.
- Downloading PayPal's public cert - PayPal has two certs, one for the live PayPal site and one for the PayPal sandbox (or beta sandbox). You use PayPal's cert to encrypt the buy-button parameters. PayPal provides links for you do download their certs. Certs are created with an expiration date. In PayPal's case, their certs will expire in 2035.
- Set your PayPal profile to only allow encrypted buttons.
For testing purposes, I have created a simple tool to do steps 1 and 3. This will allow you to create your private key, public cert and have both PayPal public certs and provide them to you in a zip file. Once you have your development working, you can then go through the steps to recreate your key and cert and re-upload to PayPal but you will have to install OpenSSL on your PC. This way you know you are the only one that has your private key. Using the private key from my tool in production will certainly work but it did originate from my computer.

Click the Buy Now and after some seconds, if you selected the Free cert, a link will display to download the zip file and if you selected a longer expiration date, you will first pay through PayPal and then return to click the zip download. This is the file:

The image shows the two PayPal public certs, the Pkcs12.p12 file, your private key (keep this secure) and your public cert (to give away). The Readme.txt file has some hints and information on the OpenSSL commands used to create these files. The p12 file is used by your code that generates your encrypted buttons. This file also should be kept secure since it contains both your private key and public cert.
The tool to create your private key and public cert is at http://www.webguild.com/PayPal.aspx (click the Certs and Keys tab). This page actually uses a PayPal buy button that uses a dynamic EWP button if you select the non-free option. The item name and price is encrypted and you will notice the personalized item name when you arrive on the PayPal site.
Wednesday, August 13, 2008
I installed Windows XP SP2 on a Virtual PC drive and ran Windows Update. It wanted to immediately update to SP3 but the update failed so I downloaded SP3 and installed it manually.
Then Windows Update wanted to do 18 more updates but they also failed. The error was:
Problem: A problem on your computer is preventing updates from being downloaded or installed
There was no error code number. I ran across a posting with a solution. I copied these statements into the clipboard and then pasted them into a command prompt window. A bunch of "Succeeded" popups displayed and I OK'd them. I retried the Windows Updated and now it worked.
regsvr32 wuapi.dll
regsvr32 wuaueng1.dll
regsvr32 wuaueng.dll
regsvr32 wucltui.dll
regsvr32 wups2.dll
regsvr32 wups.dll
regsvr32 wuweb.dll
Other things to check if this does not work is the Windows Service ("Services" in Administrative Tools) named Automatic Updates. Make sure its Status is started and its Starup Type is automatic.
Another thing that has been known to cause problems is the IE security settings. Go to IE's Internet Options->Security tab and click the Trusted Sites icon and Sites button. Uncheck Required server checkbox and add these sites, one at a time:
http://*.microsoft.com
https://*.microsoft.com
http://*.windowsupdate.com
Wednesday, May 21, 2008
I received an email from Comcast telling me that they are blocking my outgoing email:
Dear Comcast Customer:
ACTION REQUIRED: Comcast has determined that your computer(s) have been used to send unsolicited email ("spam"), which is generally an indicator of a virus. For your own protection and that of other Comcast customers, we have taken steps to prevent further transmission of spam from your computer(s).
Comcast did provide information on configuring my email client to get it to work. It's not too difficult if you are simply sending email, however my setup is not normal. The fix is basically to modify the client to send outgoing email using port 587 instead of the standard SMTP port 25. Also, the port must be configured with authentication (my Comcast ID and password).
For my situation, I run a home server to handle incoming and outgoing email so for me the fix for outgoing email is not to my client which talks to my email server (on port 25), but to fix the email server to send out using port 587 authenticated.
That was the easy part. However, my wife said she had not received any email for the last several days. I poked around and found out that incoming port 25 was also being blocked. I was not able to connect to my home server's port 25 from an external site (telnet debsrealty.com 25). My wife has her own business domain for which email was directly sent to the home server (http://www.debsrealty.com). This blockage did not affect my email to webguild.com since the mail collects on that hosted site and my home email server periodically picks up the mail via POP3.
The solution is to use a different port than 25. However, there are several steps to get this to work.
- My (dynamic) DNS name server is handled by sitelutions.com (free). They have a solution to redirect SMTP to a different port but costs $29/yr. I found a free redirection from a different company (www.rollernet.us). So the first step is to have Sitelutions redirect debsrealty.com email to mail.rollernet.us and mail2.rollernet.us with two "MX" records.
- Rollernet.us has this SMTP redirection free for a small amount of email (or $40 for a larger amount). It will also do filtering so I set up to only redirect deborah@debsrealty.com email to debsrealty on port 2525. If you receive more email than the free account allows, combine step 1 and 2 and just go with the Sitelutions $29/yr solution or check with your own nameserver company.

- The 3rd step is to modify my router to accept incoming requests on port 2525 instead of 25. Also, the router configuration will route the requests to my home server on port 25 so I did not have to change the email server to listen on port 2525. I used www.grc.com to verify port 25 was indeed blocked and 2525 was now open.
After this was all done, email started coming in for deborah@debsrealty.com. Messages sent over the last few days often are retried by the various email transports and were received. It's certainly possible that some were lost.
The rollernet site keeps a log of email transactions that is useful in verifying functionality.
Saturday, May 10, 2008
My son bought a new 160GB SATA drive for his Dell laptop to replace the original 40GB drive. I used a USB adapter to connect the drive to the laptop and used Acronis V11 Home to clone the Dell drive to the new drive.
After it completed the clone, I pulled out the old and installed the new and powered up. The drive started the boot and the Windows XP screen displayed and I thought we were home free! However, it blue-screened shortly after the Windows screen displayed.
I booted to the setup bios and it showed the new drive as 40GB, same as the old. Every tool I tried showed 40GB instead of 160GB and I have a lot of them. Reformatting, zeroing, etc would not bring the drive back to its original state.
After some hours of searching, I finally found a thread which led to the solution. The tool is called HDAT2. The problem seems to be the combination of the Dell laptop (with MediaDirect which uses a Host Protected Area (HPA) of the disk) and Acronis which had apparently problems with this HPA configuration corrupting the drive.
I burned the HDAT2 ISO to a bootable CD and booted it up to a laptop with the new drive connected via the USB adapter. HDAT2 did see the USB drive when the USB ASPI driver was selected during bootup but the option I was looking for (Set Max (HPA)) was not on the main menu like it was for the internal drive. So, I pulled out the old and popped in the new (again) and booted up the HDAT2 CD and this time the Set Max (HPA) menu item displayed for the drive.
I selected this option and it immediatly showed the discrepancy and had the Max Address field already populated with the correct value so all I had to do was type S to Save and that fixed the problem. The new drive now reported its correct size.
I will not use Acronis with this Dell for a disk clone. BTW, Acronis had worked fine for my old Dell when I upgraded its drive.
Note that the thread referenced above discussed a Seagate drive that had issues and a special procedure for dealing with 28 vs 48 bit LBA. My son's drive is a Western Digital and did not have those problems. A simple press of the S key was all that was needed in my case.
Monday, January 07, 2008
A few months ago, I attended a PayPal Developers Days conference in Miami. The seminar covered the various ways to integrate PayPal Pro into your web site to accept payments. The options included using Express Checkout which lets the user log on and choose a billing and shipping address and a method of payment; Direct Pay which allows a web site to accept credit cards cleared by PayPal without the customer having to have a PayPal account and Standard Checkout which redirects the customer to PayPal's site to log on and complete the payment. PayPal sends an IPN (Instant Payment Notification) message to a web service-like page on your site so you know you can proceed to fulfil the order.
I have been doing PayPal development for a long time so the test given at the seminar was trivial - a few hours of refresher using the supplied study guide were sufficient to quickly complete (and pass) the exam. Eventually, I got listed on the PayPal Directory.
I also got a nice PayPal shirt:)
Monday, December 24, 2007
Using Pinnacle Studio 11 (actually 11.1.1.5224) to create a DVD and then burn (burn with Pinnacle or Nero), the resulting DVD had no sound. Google search on the problem did not turn up much on this problem that others have had. Some said the latest patch solved the problem but it did not for me.
Pinnacle has a support article on this problem with no good solution. However, one of the posts I read pointed to IFOEdit as a fix. I did have good results with this technique.
First, create the DVD as an image on the hard drive but don't burn it. Edit the IFO file. In the file I created, there were two IFO files: VIDEO_TS.IFO and VTS_01_0.IFO. The one to edit is VTS_01_0.IFO. This only takes a minute.
Get the free current version of IFOEdit . Run it and click the OPEN button on the bottom. Browse to your VTS_01_0.IFO file int he VIDEO_TS folder.

What we want to do is change the audio from Mpeg-1 to Dolby AC-3. Locate the line as shown (Movie attributes for the Mpeg-1 audio). Double click the line to display the edit box and change Coding Mode from Mpeg to Dolby AC-3 and click OK.
The change will not show - it still says Mpeg-1 but click to save it anyhow (replace old version). A box will pop-up asking if you also want to save as a .BUP. Say yes. If you reopen the file in IFOEdit, it will now display the audio as Dolby.
The DVD can now be burned and will play the audio correctly.
Sunday, November 25, 2007
IIS6 supports HTTP compression of the responses sent back to user's browsers but it needs to be enabled for this to be effective. Completely enabling compression is not obvious and if you think you are enabling compression by simply checking the "Enable" checkboxes on the Internet Service Manager (ISM) you probably are in for a surprise.
These are the steps I used to get compression working and verify that what I did actually worked. I used the steps described in this DotNetJunkies link as my starting point. To verify that compression is working as expected on your server, use PipeBoost.com to request the page or the file and review its response (compressed or not). Another way is to use Fiddler to look at the HTTP headers sent to and returned from the web server.
You will have to edit the IIS metabase to add the file types to the existing list for compression. To allow you to edit the metabase while IIS is running, you have to enable editing of the Metabase in the ISM. Right-click the Server->Properties->Enable Direct Metabase Edit. Check the box and click OK.

Now right-click Web Sites->Properties->Services tab.

This shows I have chosen to compress both dynamic (application) and static files. I left the temp directory (used for caching compressed versions of the static files) as the default. I also limited my cache size. Change these if desired. There is some overhead in checking to compress dynamic files since each web page request will require some processing time to save in bandwidth.
By default, the important file types are not compressed (.aspx, .css, .js, etc) so we will add these types with the metabase edit shortly.
Next, select the Web Service Extensions and add a new extension to identify the gzip.dll. By convention, I called this Http Compression and the location of the dll is in your Windows folder \System32\inetsrv\gzip.dll as shown below. Set the checkbox to allow and click OK.

Now we can edit the Metabase. Navigate to the same inetsrv folder from above. For safety, make a copy of the MetaBase.xml file. Edit with your favorite editor. Find the section for gzip (not the one for deflate) and add the lines highlighted:

The lines added have tabs followed by the types on separate lines. Save the file.
The final step is to do an IISRESET. This forces IIS to re-load the edited Metabase.xml and enable the compression.
You can now go to the PipeBoost.com site and enter your URL to verify that it displays that the page Document Status is Compressed. You can individually try an aspx page and a css or js page to make sure both dynamic and static pages are compressed. You can also start up Fiddler and browse to your page and verify the components are compressed. The browser must tell the server that it can handle compression (most current popular browsers) with a header

If you don't see the Content-Encoding: gzip response header for the file, compression is not correctly enabled.
You can also use Fiddler to see what the size of the request would be both compressed or not by changing the radion button:

Thursday, November 22, 2007
After returning from dinner out one evening, my wife and I entered the house and then heard a loud noise in the garage. We re-opened the door and looked in and saw nothing out of place; no shelves crashed down nor garden tools fell over.
The next morning we found out what happened. The automatic garage door opener would not open the door more than about a foot and then it reversed. I disengaged the opener and tried to open the garage door manually, but it seemed to be stuck. Then Deborah noticed that the right torsion spring above the door was broken in two.
I described how I replaced the springs (with video) at this web page: http://www.webguild.com/DIYClinic/.
Thursday, October 04, 2007
I am porting a VS2005 web site from Visual Studio 2005 IIS6 to Visual Studio 2008 (Beta 2) IIS7 on Vista and have encountered several issues.
I am doing this in several steps to ease the migration headaches.
- Move the web application project web site from IIS6 (Windows Server 2003) to IIS7 (Vista Business).
- Bring up the web solution in VS2008 to do the conversion.
- Change each project in the solution to use Framework 3.0 (and verify functionality)
- Change each project in the solution to use Framework 3.5 (and verify functionality)
- Verify that debugging works
Some issues were identified in the various steps as expected.
Issue #1 - Web Config HttpHandler
Use <Handler> instead of <HttpHandler>
Issue #2 - "Request is not available" in this context Trap
I am getting this error in several places in my code. These are class library methods that sometimes run with no Request object, perhaps from a win form instead of a web app. They all test for the existence of the Request by looking at HttpContext.Current and if null, skips the code that uses HttpContext.Current.Request. It seems like in IIS7, this test is no longer sufficient. It appears that HttpContext.Current may be non-null but HttpContext.Current.Request references cause the above trap.
For example, this traps in IIS7 and works fine in IIS6:
if (HttpContext.Current != null) // No HttpContext if entered via RemovedCallback()
{
string host = HttpContext.Current.Request.Url.Host.ToLower();
if (host == "www.mydomain.com") return;
}
To get this to work, I changed the IF to a TRY/CATCH. Is there a more elegant way? I generally try to avoid TRY/CATCH.
try
{
string host = HttpContext.Current.Request.Url.Host.ToLower();
if (host == "www.mydomain.com") return;
}
catch{}
Follow Up: This seems to work - check the Handler property for null:
if (HttpContext.Current != null && // No HttpContext if entered via RemovedCallback()
HttpContext.Current.Handler != null)
{
string host = HttpContext.Current.Request.Url.Host.ToLower();
if (host == "www.mydomain.com") return;
}
Issue #3 - Asynchronous Calls to Web Service(s)
The model changed from Framework 1.1 to 2.0. The auto-generated proxy to call a web service no longer had two methods I was using called begin<websvcname> and end<websvcname>.
The web service was used to clear the cache in each of the web farm servers. I wanted to call each without waiting for a response to overlap the request. When the responses finally came in, if there was an error, it was logged.
There were too many issues in converting to the newer event-based model (static method needed to be instance method, no way to have "Async=True" on the @Page, unsure if the overlapped requests were supported, etc). So the solution was to simply copy the old generated code for the begin and end into the newly generated proxy.
/// <remarks/>
public System.IAsyncResult BeginCachePurge(CachePurgeType cachePurgeType,
string parameter, System.AsyncCallback callback, object asyncState)
{
return this.BeginInvoke("CachePurge", new object[] {
cachePurgeType,
parameter}, callback, asyncState);
}
/// <remarks/>
public bool EndCachePurge(System.IAsyncResult asyncResult)
{
object[] results = this.EndInvoke(asyncResult);
return ((bool)(results[0]));
}
[This post is in progress - Gary]