Analytics


Google

Tuesday, December 8, 2009

Migrating from IIS 5/6 to IIS 7 manually

In IIS 7, a new utility is introduced  it is known as appcmd.

In order to run the commands below effectively, you need to open a command prompt session (running as Administrator).  I will not repeat what I have covered in the previous article on IIS 5 to IIS 6 but following the concept covered there, just change some minor approach and use the new command.

It is located in %windir%/system32/inetsrv/appcmd.exe

To get the format for the files needed to configure your virtual directory, the easiest way is to use the command as follows:

%windir%/system32/inetsrv/appcmd list vdir /xml

The output will look like this:

<?xml version="1.0" encoding="UTF-8"?>
<appcmd>
    <VDIR physicalPath="%SystemDrive%\inetpub\wwwroot" path="/" APP.NAME="Default Web Site/" VDIR.NAME="Default Web Site/" />
    <VDIR physicalPath="C:\webfiles\t2" path="/test3" APP.NAME="Default Web Site/" VDIR.NAME="Default Web Site/test3" />
    <VDIR physicalPath="C:\webfiles\t3" path="/test4" APP.NAME="Default Web Site/" VDIR.NAME="Default Web Site/test4" />
    <VDIR physicalPath="C:\webfiles\t4" path="/test5" APP.NAME="Default Web Site/" VDIR.NAME="Default Web Site/test5" />
    <VDIR physicalPath="C:\webfiles\t1" path="/" APP.NAME="Default Web Site/test2" VDIR.NAME="Default Web Site/test2/" />
</appcmd>

A few things to note.  If you want to make the virtual folder an application, then you need to change the APP.Name  to include the application name as in the case above where t2 is known as test2.  Also the path is the path relative to the application.

You can then copy this listing and use it as a template for your migration.  To get a list of application pool, use the following command:

%windir%\system32\inetsrv\appcmd list apppool /xml

The output will look like this:

<?xml version="1.0" encoding="UTF-8"?>
<appcmd>
    <APPPOOL APPPOOL.NAME="DefaultAppPool" PipelineMode="Integrated" RuntimeVersion="v2.0" state="Started" />
    <APPPOOL APPPOOL.NAME="Classic .NET AppPool" PipelineMode="Classic" RuntimeVersion="v2.0" state="Started" />
    <APPPOOL APPPOOL.NAME="test" PipelineMode="Integrated" RuntimeVersion="v2.0" state="Started" />
    <APPPOOL APPPOOL.NAME="frame1.1" PipelineMode="Integrated" RuntimeVersion="" state="Started" />
</appcmd>

If you want to add as an application folder, a quicker way is to use following command to get the default format:


%windir%\system32\inetsrv\appcmd list app /xml /config

Output will look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<appcmd>
    <APP path="/" APP.NAME="Default Web Site/" APPPOOL.NAME="DefaultAppPool" SITE.NAME="Default Web Site">
        <application path="/">
            <virtualDirectoryDefaults />
            <virtualDirectory path="/" physicalPath="%SystemDrive%\inetpub\wwwroot" />
            <virtualDirectory path="/test3" physicalPath="C:\webfiles\t2" />
            <virtualDirectory path="/test4" physicalPath="C:\webfiles\t3" />
            <virtualDirectory path="/test5" physicalPath="C:\webfiles\t4" />
        </application>
    </APP>
    <APP path="/test2" APP.NAME="Default Web Site/test2" APPPOOL.NAME="test" SITE.NAME="Default Web Site">
        <application path="/test2" applicationPool="test">
            <virtualDirectoryDefaults />
            <virtualDirectory path="/" physicalPath="C:\webfiles\t1" />
        </application>
    </APP>
</appcmd>

Once you have all the above format, you can then copy into a text editor and add in the required virtual folder or apps that you want to add.  It is probably easier to manually configure the application pools and then use the appcmd to add in the virtual applications.  Once you have your commands ready, use the following command:

For adding virtual directory, type the following command and then it will put you into the next line.  When it does that, paste your XML string to the console.  Once the xml is pasted, add one or two lines at the bottom and press Control Z to mark the end.

%windir%\system32\inetsrv\appcmd add vdir /in


Same with adding app and apppools.


%windir%\system32\inetsrv\appcmd add app /in

Tuesday, October 27, 2009

Inserting formatted text in Gmail

In order to create formatted text in Google Mail - especially tables, first create the table in Excel then copy from Excel and paste it into mail you are composing GMail. Note that this will only work if you are using FireFox or Internet Explorer. It does not work with Chrome.

If you are using FireFox, you have an additional ability to delete content from the table by column or row.

One problem I have is when it is forwarded to Lotus NOTES, the fonts appear to run so some of the rows may contain strange highlights or fonts.

Friday, October 23, 2009

Managing Logs in Apache

The following is an article providing some tips on how to manage logs in Apache:

http://www.webreference.com/programming/Apache-Logging/

Highlighting Incoming Mails in GMail

Many of us are using Gmail as our main email system whether it is for personal or because the company we work for has outsourced the email system to Google. Since more and more communication is done through email, very often we receive many emails each day. As a result, we sometimes miss urgent email such as emails from a key client or from our bosses.

There is an easy way to help us highlight mails from specific senders or for specific subject; it is through the use of labels.

  1. For this to be effective, you need to first go and enable a gmail lab feature called Custom Label Colors.
  2. Next create the required filters. You can create filter to look out for mails from a specific sender or subjects containing certain keywords. The filter should have an action to apply a specific label (For example, “Key Customer”, “Management”, “Bosses Mail”); you can apply an existing label and create the label when you create your filter.
  3. Next click on the white check box next the label you created and select the color you want.

In future when you receive email that match the criteria specified in step 2, you can easily see it in your inbox.

This is the same article I wrote in Triond.

Friday, October 16, 2009

Programmer's Journal - Chapter 10

Chapter 10 - Protocols (SMTP, FTP, HTTP)

The framework supports many kinds of Internet protocol. We have previously covered web services. Now let us look at a few more common protocols. SMTP for sending mail, FTP for file transfer and HTTP for obtaining information from other web pages.
SMTP (or Sending Mail)

SMTP stands for Simple Mail Transfer Protocol and is used to send mail. It uses port 25. When using this, you need to be aware that some antivirus software or firewalls will block this port and you may need to disable the blocking before you can send mail. This is because a lot of viruses also use this protocol to propagate themselves.

If you need to send a quick mail (which consist of text only), you can just use the simple function:

SMTP.Send(from, toMail, subject, body).

Framework 1.1 Example
The following is an example of sending attachment:

Imports Microsoft.VisualBasic
Imports System
Imports System.IO
Imports System.Web.Mail
Imports System.Reflection


' Program: TestMail_1.1
' Author: Strovek
' Date: Mar 27, 2006
' Revised:
' Simple program for sending email - using codes for Framework 1.1
'
' ===================================================================

<Assembly: AssemblyVersionAttribute("1.0.0")>
<Assembly: AssemblyFileVersion("1.0.0")>
<Assembly: AssemblyCompanyAttribute("Programmer's Journal")>
<Assembly: AssemblyProductAttribute("FTP test")>

Module Module1

Public Function prgVersion() As String
Return _
System.Diagnostics.FileVersionInfo.GetVersionInfo(_
System.Reflection.Assembly.GetExecutingAssembly.Location).FileVersion
End Function

Sub Main()
Dim SMTPSrv As String
Dim addr As String
Console.WriteLine("Test Send Mail - Version " & prgVersion())

Try
SMTPSrv = System.Configuration.ConfigurationSettings.AppSettings("SMTPSrv")
If Len(SMTPSrv) <= 0 Then
Throw New Exception("No SMTP Server provided")
End If
Console.WriteLine("smtp server is " & SMTPSrv)

addr = System.Configuration.ConfigurationSettings.AppSettings("Rcpt")
If Len(addr) <= 0 Then
Throw New Exception("No address provided")
End If

Dim Message As System.Web.Mail.MailMessage = New System.Web.Mail.MailMessage
Message.To = addr
Message.From = addr
Message.Subject = "Test Mail - for testing SMTP"
Message.Body = "Just a test message"
Message.Attachments.Add(New MailAttachment("c:\test2.txt"))
SmtpMail.SmtpServer = SMTPSrv
SmtpMail.Send(Message)
Console.WriteLine("Message sent")

Catch ex As Exception
Console.WriteLine("Error " & ex.Message)
End Try

Console.WriteLine("End Program")
End Sub

End Module


In the above example, the attachment is provided via the filename. This is the only option available in Framework 1.1.

The sample above uses the config file to provide the SMTP server name and also the receipients name. One of the services provided by IIS is SMTP; this is what we are using to send the mail. The config file is as follows:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="SMTPSrv" value="localhost" />
<add key="Rcpt" value="bteoh1@hotmail.com" />
</appSettings>
</configuration>


Framework 2.0 Example
The new namespace System.Net.Mail is introduced in Framework 2.0 to replace System.Web.Mail namespace in Framework 1.1.

The following is a sample of the code using the new namespace.

Imports Microsoft.VisualBasic
Imports System
Imports System.IO
Imports System.Net.Mail
Imports System.Reflection


' Program: TestMail_2.0
' Author: Strovek
' Date: Mar 27, 2006
' Revised:
' Simple program for sending email - using codes for Framework 1.1
'
' ===================================================================

<Assembly: AssemblyVersionAttribute("1.0.0")>
<Assembly: AssemblyFileVersion("1.0.0")>
<Assembly: AssemblyCompanyAttribute("Programmer's Journal")>
<Assembly: AssemblyProductAttribute("FTP test")>

Module Module1

Public Function prgVersion() As String
Return _
System.Diagnostics.FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly.Location).FileVersion
End Function

Sub Main()
Dim SMTPSrv As String
Dim addr As String
Dim attch As Attachment
Console.WriteLine("Test Send Mail - Version " & prgVersion())

Try
SMTPSrv = System.Configuration.ConfigurationManager.AppSettings("SMTPSrv")
If Len(SMTPSrv) <= 0 Then
Throw New Exception("No SMTP Server provided")
End If
Console.WriteLine("smtp server is " & SMTPSrv)

addr = System.Configuration.ConfigurationManager.AppSettings("Rcpt")
If Len(addr) <= 0 Then
Throw New Exception("No address provided")
End If

Dim fromAddr As New MailAddress(addr)
Dim toAddr As New MailAddress(addr)
Dim Message As New System.Net.Mail.MailMessage(fromAddr, toAddr)

Message.Subject = "Test Mail - for testing SMTP"
Message.Body = "Just a test message"
Message.Attachments.Add(New Attachment("c:\test2.txt"))

Dim strm As New MemoryStream
Dim sw As New StreamWriter(strm)
sw.WriteLine("Line 1")
attch = New Attachment(strm, "test3.txt")
Message.Attachments.Add(attch)

Dim SMTP As New SmtpClient(SMTPSrv)
SMTP.Send(Message)
sw.Close()
Console.WriteLine("Message sent")

Catch ex As Exception
Console.WriteLine("Error " & ex.Message)
End Try

Console.WriteLine("End Program")
End Sub

End Module


Note the change in the constructor. This constructor is used because the .to method is read-only so has to be set in the constructor. The Attachment introduced in Framework 2.0 to replace mail-attachment allows passing a stream in the constructor. This is allows you to create an attachment in memory and send it (as shown in the example above).

The config file is identical to the one used in the previous example.

FTP
FTP is short for File Transfer Protocol and is used primarily for transferring files to and from a remote ftp server. The support was provided in Framework 1.1. However, it was difficult because you have to implement your own code to handle the FTP protocol.

The ftp protocol code has been implemented in Framework 2.0. The following is a sample of transferring a file to and from the local ftp server:

' doFTP
' Author Strovek
' Date Apr 03, 2006
' Revised
' For performing simple FTP
' ===============================================================================


Imports Microsoft.VisualBasic
Imports System
Imports System.IO
Imports System.Text
Imports System.Net
Imports System.Reflection

<Assembly: AssemblyVersionAttribute("1.0.0")>
<Assembly: AssemblyFileVersion("1.0.0")>
<Assembly: AssemblyCompanyAttribute("Programmer's Journal")>
<Assembly: AssemblyProductAttribute("FTP test")>


Public Class doFTP

Dim ftp As FtpWebRequest

Public Shared Function prgVersion() As String
Return _
System.Diagnostics.FileVersionInfo.GetVersionInfo(_
System.Reflection.Assembly.GetExecutingAssembly.Location).FileVersion
End Function

Public Shared Sub main()
Dim ftpSrv As String = Nothing
Dim ftpUsr As String = Nothing
Dim ftpPwd As String = Nothing
Dim ftpDir As String = Nothing
Dim fSrcName As String = "C:\icons\icons.bmp"
Dim fTgtName As String = "icons.bmp"
Dim fTgtName2 As String = "c:\tx\icons.bmp"

Console.WriteLine("doFTP - Version " & prgVersion())

Try

ftpSrv = System.Configuration.ConfigurationManager.AppSettings("ftpSrv")
ftpUsr = System.Configuration.ConfigurationManager.AppSettings("ftpUsr")
ftpPwd = System.Configuration.ConfigurationManager.AppSettings("ftpPwd")
ftpDir = System.Configuration.ConfigurationManager.AppSettings("ftpDir")

If ftpSrv.Contains("ftp://") = False Then
ftpSrv = "ftp://" & ftpSrv
End If

Dim ftpObj As New doFTP
ftpObj.uploadFile(ftpSrv, ftpUsr, ftpPwd, "blank", fSrcName, fTgtName)
ftpObj.downloadFile(ftpSrv, ftpUsr, ftpPwd, "blank", fTgtName, fTgtName2)

Catch ex As Exception
Console.WriteLine(ex.Message)
End Try

Console.WriteLine("End Program")

End Sub

' for Uploading file
Sub uploadFile(ByVal ftpSrv As String, ByVal usrName As String, _
ByVal usrPwd As String, ByVal ftpDir As String, _
ByVal src As String, ByVal tgt As String)

Dim ftpUrl As New StringBuilder

If ftpSrv Is Nothing Then
Throw New Exception("[upLoadFile01]ftp server not provided")
End If
If usrName Is Nothing Then
Throw New Exception("[upLoadFile02]User Name not provided")
End If
If usrPwd Is Nothing Then
Throw New Exception("[upLoadFile03]User Password not provided")
End If
If src Is Nothing Then
Throw New Exception("[upLoadFile04]Source FileName not provided")
End If
If tgt Is Nothing Then
Throw New Exception("[upLoadFile05]Target filename not provided")
End If

Dim ftpStream As Stream = Nothing
Dim fStream As FileStream = Nothing
Dim ftpResponse As FtpWebResponse = Nothing

ftpUrl.Append(Trim(ftpSrv))
If Trim(ftpSrv).EndsWith("/") = False Then
ftpUrl.Append("/")
End If
ftpUrl.Append(Trim(ftpDir))
If Trim(ftpDir).EndsWith("/") = False Then
ftpUrl.Append("/")
End If
ftpUrl.Append(tgt)

Try
Console.WriteLine(ftpUrl.ToString)
ftp = WebRequest.Create(ftpUrl.ToString)
ftp.Credentials = New NetworkCredential(usrName, usrPwd)
ftp.Method = WebRequestMethods.Ftp.UploadFile
ftpStream = ftp.GetRequestStream

fStream = File.Open(src, FileMode.Open)

Dim buffer(1024) As Byte
Dim bytesRead As Integer
While True
bytesRead = fStream.Read(buffer, 0, buffer.Length)
If bytesRead = 0 Then
Exit While
End If
ftpStream.Write(buffer, 0, bytesRead)
End While

' The request stream must be closed before getting the response.
ftpStream.Close()
fStream.Close()

ftpResponse = ftp.GetResponse()
Console.WriteLine(ftpResponse.StatusDescription)
Console.WriteLine("Upload successful")
Catch ex As Exception

' Need to check here since finally clause will
' never be reached because of the throw exception
If fStream IsNot Nothing Then
fStream.Close()
End If
If ftpStream IsNot Nothing Then
ftpStream.Close()
End If

Console.WriteLine(ex.StackTrace)
Throw New Exception("[upLoadFile06]" & ex.Message)
Finally
If fStream IsNot Nothing Then
fStream.Close()
End If
If ftpStream IsNot Nothing Then
ftpStream.Close()
End If
End Try

End Sub

Sub downloadFile(ByVal ftpSrv As String, ByVal usrName As String, _
ByVal usrPwd As String, ByVal ftpDir As String, _
ByVal src As String, ByVal tgt As String)

Dim ftpUrl As New StringBuilder

If ftpSrv Is Nothing Then
Throw New Exception("[downloadFile01]ftp server not provided")
End If
If usrName Is Nothing Then
Throw New Exception("[downloadFile02]User Name not provided")
End If
If usrPwd Is Nothing Then
Throw New Exception("[downloadFile03]User Password not provided")
End If
If src Is Nothing Then
Throw New Exception("[downloadFile04]Source FileName not provided")
End If
If tgt Is Nothing Then
Throw New Exception("[downloadFile05]Target filename not provided")
End If

Dim ftpStream As Stream = Nothing
Dim fStream As FileStream = Nothing
Dim ftpResponse As FtpWebResponse = Nothing

ftpUrl.Append(Trim(ftpSrv))
If Trim(ftpSrv).EndsWith("/") = False Then
ftpUrl.Append("/")
End If
ftpUrl.Append(Trim(ftpDir))
If Trim(ftpDir).EndsWith("/") = False Then
ftpUrl.Append("/")
End If
ftpUrl.Append(src)

Try
Console.WriteLine(ftpUrl.ToString)
ftp = WebRequest.Create(ftpUrl.ToString)
ftp.Credentials = New NetworkCredential(usrName, usrPwd)
ftp.Method = WebRequestMethods.Ftp.DownloadFile
ftpResponse = ftp.GetResponse
ftpStream = ftpResponse.GetResponseStream

Dim buffer(1024) As Byte
Dim bytesRead As Integer
fStream = File.Create(tgt)
While True
bytesRead = ftpStream.Read(buffer, 0, buffer.Length)
If bytesRead = 0 Then
Exit While
End If
fStream.Write(buffer, 0, bytesRead)
End While

' The request stream must be closed before getting the response.
ftpStream.Close()
fStream.Close()

Console.WriteLine("download successful")
Catch ex As Exception

' Need to check here since finally clause will
'never be reached because of the throw exception
If fStream IsNot Nothing Then
fStream.Close()
End If
If ftpStream IsNot Nothing Then
ftpStream.Close()
End If

Console.WriteLine(ex.StackTrace)
Throw New Exception("[downloadFile06]" & ex.Message)
Finally
If fStream IsNot Nothing Then
fStream.Close()
End If
If ftpStream IsNot Nothing Then
ftpStream.Close()
End If
End Try

End Sub

End Class


The following is the config file used with the sample above:

<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="ftpSrv" value="ftp://localhost"/>
<add key="ftpUsr" value="anonymous"/>
<add key="ftpPwd" value="t@t.com"/>
<add key="ftpDir" value="/blank/"/>
</appSettings>
</configuration>



In the above sample, the uploadFile subroutine shows how to upload a file to the ftp server and downloadFile downloads the file from the ftp server. As shown in the example above, you need to provide the target server filename together with the directory and the server name. The same with when downloading the file, you need to provide the fully qualified path as in ftp://localhost/blank/test.txt. The sample uses only ASCII transfer. In order to use binary file transfer, set the UseBinary property of the FtpWebRequest object to True. Note that all transfer used here are sent via clear text (without encryption). If your server supports SSL, you can set the EnableSSL property to true. In the case of SSL enabled, then the protocol used with ftps. There is another protocol called sftp - i.e. ftp over SSH (Secure Shell). The implementation is provided with the Framework (so you either have to provide your own implementation or obtain a third party implementation).

HTTP (also known as screen scrapping)

HTTP protocol is typically used either for screen scrapping, where you obtain information from other web pages or to automated submission of information to other web sites. However, many web developers have come out with mechanism to prevent programs from using their web sites with JavaScript, image - requiring the user to interprete and key in the values.

Fiddler
Before you can perform screen scrapping you need to know what needs to be transmitted to the web page. Microsoft provides a free tool (to be used with Internet Explorer) to do this - it is called Fiddler.

For the purpose of illustration, a simple page was created for the purpose of illustration:

Before submit:



After Submit:



This is what you see in Fiddler:



Notice that what is sent to the server.

Code Sample
The following is a code sample of how we can use this information:

' ScrapScrn
' Author Strovek
' Date Apr 20, 2006
' Revised
' For performing simple FTP
' ===============================================================================

Imports Microsoft.VisualBasic
Imports System
Imports System.IO
Imports System.Net
Imports System.Text
'Imports System.Web

Module ScrapScrn
Dim rqst As HttpWebRequest
Dim rsp As HttpWebResponse
Private header As WebHeaderCollection
Private cookies As CookieContainer = New CookieContainer()
Const url As String = "http://localhost/pj/chapter10/simplesubmit.aspx"

Sub main(ByVal CmdArgs() As String)

Console.WriteLine("Program start")
Try
postPage()
Catch ex As Exception
Console.WriteLine("Error " & vbNewLine & ex.Message)
End Try
Console.WriteLine("End Program")

End Sub

Sub postPage()

Dim cookies As CookieContainer = New CookieContainer()
rqst = WebRequest.Create(url)
rsp = rqst.GetResponse
Dim rspStr As String
Dim sReader As New StreamReader(rsp.GetResponseStream)
header = rqst.Headers ' Obtain the header values from the request
cookies = rqst.CookieContainer ' Obtain Cookie from the request
rspStr = sReader.ReadToEnd
sReader.Close()
Console.WriteLine("Response received" & vbNewLine & rspStr)

Dim key As String

Console.WriteLine("header content is as follows")
For Each key In header.AllKeys
Console.WriteLine("Key is {0} and value is {1}", key, header.Item(key))
Next

Dim viewState As String = ExtractViewState(rspStr)
Console.WriteLine("viewState is " & viewState)

Dim postData As String = String.Format("__VIEWSTATE={0}&txtEntry={1}&btnSubmit={2}", _
viewState, "test", "Submit")
Console.WriteLine("postData is " & postData)

rqst = WebRequest.Create(url)
'rqst.Headers = header ' Repopulate the header values from the previous request
rqst.CookieContainer = cookies ' Repopulate the cookies from the previous request
rqst.ContentType = "application/x-www-form-urlencoded"
rqst.Method = "POST"

Dim sw As New StreamWriter(rqst.GetRequestStream)
sw.Write(postData)
sw.Close()

rsp = rqst.GetResponse
sReader = New StreamReader(rsp.GetResponseStream)
rspStr = sReader.ReadToEnd
sReader.Close()
Console.WriteLine("Data after post" & vbNewLine & rspStr)

End Sub

Function ExtractViewState(ByVal strParam As String) As String
Dim ViewStateDelimiter As String = "__VIEWSTATE"
Dim valueDelimiter As String = "value="""

Dim viewStateNamePosition As Integer = strParam.IndexOf(ViewStateDelimiter)
Dim viewStateValuePosition As Integer = strParam.IndexOf( _
valueDelimiter, viewStateNamePosition)

Dim viewStateStartPosition As Integer = viewStateValuePosition + valueDelimiter.Length
Dim viewStateEndPosition As Integer = strParam.IndexOf("""", viewStateStartPosition)

Dim returnVal As String = _
System.Web.HttpUtility.UrlEncodeUnicode(strParam.Substring(viewStateStartPosition, _
viewStateEndPosition - viewStateStartPosition))

Return returnVal
End Function

End Module


The first portion of the code performs a get to the web page to obtain the headers, cookies etc. See below:

Dim cookies As CookieContainer = New CookieContainer()
rqst = WebRequest.Create(url)
rsp = rqst.GetResponse
Dim rspStr As String
Dim sReader As New StreamReader(rsp.GetResponseStream)
header = rqst.Headers ' Obtain the header values from the request
cookies = rqst.CookieContainer ' Obtain Cookie from the request
rspStr = sReader.ReadToEnd
sReader.Close()
Console.WriteLine("Response received" & vbNewLine & rspStr)


Since the web page was written in ASP.Net, it contains a hidden field called ViewState, we need to send back this value when we post the information. In order to that, we need to first get the value from the original response. The view state is as follows:

<input type="hidden" name="__VIEWSTATE" value="dDwxMzMzMTE3MDk3Ozs+ouZtBeP5/4BlYpWcfFxvgG8hQ8c=" />

To do that, first find the location of _VIEWSTATE and then find the location of the first value=" after that. Then get the value until the end of the quote. The function to do that is as follows:

Function ExtractViewState(ByVal strParam As String) As String
Dim ViewStateDelimiter As String = "__VIEWSTATE"
Dim valueDelimiter As String = "value="""

Dim viewStateNamePosition As Integer = strParam.IndexOf(ViewStateDelimiter)
Dim viewStateValuePosition As Integer = strParam.IndexOf( _
valueDelimiter, viewStateNamePosition)

Dim viewStateStartPosition As Integer = viewStateValuePosition + valueDelimiter.Length
Dim viewStateEndPosition As Integer = strParam.IndexOf("""", viewStateStartPosition)

Dim returnVal As String = _
System.Web.HttpUtility.UrlEncodeUnicode(strParam.Substring(viewStateStartPosition, _
viewStateEndPosition - viewStateStartPosition))

Return returnVal
End Function


Finally, construct the string you want to post, in this case is:

__VIEWSTATE=dDwxMzMzMTE3MDk3Ozs%2BouZtBeP5%2F4BlYpWcfFxvgG8hQ8c%3D&txtEntry=testing&btnSubmit=Submit

Another thing to note between the original get and the final post, the contenttype has changed.

The following is the original content type:



The following is the content-type when posting:



The following is the rest of the code:


Dim postData As String = String.Format("__VIEWSTATE={0}&txtEntry={1}&btnSubmit={2}", _
viewState, "test", "Submit")
Console.WriteLine("postData is " & postData)

rqst = WebRequest.Create(url)
'rqst.Headers = header ' Repopulate the header values from the previous request
rqst.CookieContainer = cookies ' Repopulate the cookies from the previous request
rqst.ContentType = "application/x-www-form-urlencoded"
rqst.Method = "POST"

Dim sw As New StreamWriter(rqst.GetRequestStream)
sw.Write(postData)
sw.Close()

rsp = rqst.GetResponse
sReader = New StreamReader(rsp.GetResponseStream)
rspStr = sReader.ReadToEnd
sReader.Close()
Console.WriteLine("Data after post" & vbNewLine & rspStr)


In the above sample, we are sending back all the cookies that were obtained from the original request. The header was not returned because the contenttype is part of the header and should be changed.

As with FTP, we can also enableSSL to perform https.

Friday, October 9, 2009

HTML 5

HTML 5 provides many of the enhancements to improve our browsing experience. The following are links on the added features:

Application Caching
Summary of the features

One of the challenge, however, is identifying which browser current supports it. Thankfully, it can easily be found here.

Friday, October 2, 2009

Mounting a new drive in Sun Solaris

If you are creating a new virtual drive in VMWare or installing a new disk, you need to first detech the disk. This can be done with the command:

#devfsadm -v

Once you detect the disk you can then format the disk using the format command:

#format

Screen example shown below:



# format
Searching for disks...done


AVAILABLE DISK SELECTIONS:
0. c1t0d0

/pci@0,0/pci15ad,1976@10/sd@0,0
1. c1t1d0
testVol
/pci@0,0/pci15ad,1976@10/sd@1,0
Specify disk (enter its number):
1
selecting c1t1d0:
testVol
[disk formatted]


FORMAT MENU:
disk - select a disk
type - select (define) a disk type
partition - select (define) a partition table
current - describe the current disk
format - format and analyze the disk
fdisk - run the fdisk program
repair - repair a defective sector
label - write label to the disk
analyze - surface analysis
defect - defect list management
backup - search for backup labels
verify - read and display labels
save - save new disk/partition definitions
inquiry - show vendor, product and revision
volname - set 8-character volume name
!
- execute , then return
quit

format> partition


PARTITION MENU:
0 - change `0' partition
1 - change `1' partition
2 - change `2' partition
3 - change `3' partition
4 - change `4' partition
5 - change `5' partition
6 - change `6' partition
7 - change `7' partition
select - select a predefined table
modify - modify a predefined partition table
name - name the current table
print - display the current table
label - write partition map and label to the disk
!
- execute , then return
quit

partition> modify
Select partitioning base:
0. Current partition table (original)
1. All Free Hog
Choose base (enter number) [0]?
1

Part Tag Flag Cylinders Size Blocks
0 root wm 0 0 (0/0/0) 0
1 swap wu 0 0 (0/0/0) 0
2 backup wu 0 - 1301 9.97GB (1302/0/0) 20916630
3 unassigned wm 0 0 (0/0/0) 0
4 unassigned wm 0 0 (0/0/0) 0
5 unassigned wm 0 0 (0/0/0) 0
6 usr wm 0 0 (0/0/0) 0
7 unassigned wm 0 0 (0/0/0) 0
8 boot wu 0 - 0 7.84MB (1/0/0) 16065
9 alternates wm 0 0 (0/0/0) 0

Do you wish to continue creating a new partition
table based on above table[yes]?

Free Hog partition[6]?
Enter size of partition '0' [0b, 0c, 0.00mb, 0.00gb]:
Enter size of partition '1' [0b, 0c, 0.00mb, 0.00gb]:
Enter size of partition '3' [0b, 0c, 0.00mb, 0.00gb]:
Enter size of partition '4' [0b, 0c, 0.00mb, 0.00gb]:
9.9gb
Enter size of partition '5' [0b, 0c, 0.00mb, 0.00gb]:
Enter size of partition '7' [0b, 0c, 0.00mb, 0.00gb]:

Part Tag Flag Cylinders Size Blocks
0 root wm 0 0 (0/0/0) 0
1 swap wu 0 0 (0/0/0) 0
2 backup wu 0 - 1301 9.97GB (1302/0/0) 20916630
3 unassigned wm 0 0 (0/0/0) 0
4 unassigned wm 1 - 1293 9.90GB (1293/0/0) 20772045
5 unassigned wm 0 0 (0/0/0) 0
6 usr wm 1294 - 1301 62.75MB (8/0/0) 128520
7 unassigned wm 0 0 (0/0/0) 0
8 boot wu 0 - 0 7.84MB (1/0/0) 16065
9 alternates wm 0 0 (0/0/0) 0

Okay to make this the current partition table[yes]?
Enter table name (remember quotes):
"testDisk"

Ready to label disk, continue? yes

partition> quit


FORMAT MENU:
disk - select a disk
type - select (define) a disk type
partition - select (define) a partition table
current - describe the current disk
format - format and analyze the disk
fdisk - run the fdisk program
repair - repair a defective sector
label - write label to the disk
analyze - surface analysis
defect - defect list management
backup - search for backup labels
verify - read and display labels
save - save new disk/partition definitions
inquiry - show vendor, product and revision
volname - set 8-character volume name
!
- execute , then return
quit
format>
save
Saving new disk and partition definitions
Enter file name["./format.dat"]:

format> quit


Next create a file system:

# newfs c1t1d0s4

note that you use the device name you see in the format screen and add s4 for the slice 4 (or partition 4).

Screenshot below:



newfs: /dev/rdsk/c1t1d0s4 last mounted as
newfs: construct a new file system /dev/rdsk/c1t1d0s4: (y/n)? y
Warning: 820 sector(s) in last cylinder unallocated
/dev/rdsk/c1t1d0s4: 20772044 sectors in 3381 cylinders of 48 tracks, 128 sectors
10142.6MB in 212 cyl groups (16 c/g, 48.00MB/g, 5824 i/g)
super-block backups (for fsck -F ufs -o b=#) at:
32, 98464, 196896, 295328, 393760, 492192, 590624, 689056, 787488, 885920,
19858720, 19957152, 20055584, 20154016, 20252448, 20350880, 20449312,
20547744, 20646176, 20744608






checking the disk is optional:

# fsck /dev/rdsk/c1t1d0s4


** /dev/rdsk/c1t1d0s4
** Last Mounted on
** Phase 1 - Check Blocks and Sizes
** Phase 2 - Check Pathnames
** Phase 3a - Check Connectivity
** Phase 3b - Verify Shadows/ACLs
** Phase 4 - Check Reference Counts
** Phase 5 - Check Cylinder Groups
2 files, 9 used, 10228265 free (17 frags, 1278531 blocks, 0.0% fragmentation)




Next make the mount mount - using mkdir
# mkdir tmpMount

Finally, mount the new disk

# mount /dev/dsk/c1t1d0s4 /tmpMount





Configuring Sun Solaris x86 in vmware for 64 bit

By default when you install SunSolaris x86 both 32 bit and 64 bit is provided. When configuring it within VMWare we can also select whether we want to have 32 bit or 64 bit.

However, even after selecting that we sometimes end up with 32 bit. The reason is the BIOS setting, we need to go into the bios of the computer and enable Virtual Machine support. Only after that will the Solaris run in 64 bit. Even if you have installed it previously when the bios Virtual machine support is not turned on.

To check if it is running 64 bit, just type:

/usr/bin/isainfo -kv

If it is 64 bit, you will see the output as follows:

64-bit amd64 kernel modules

Tuesday, September 29, 2009

Reference site to Learn WebLogic

I found the following web site that provides simple instructions to help learn about web logic. The following is the URL of the first page. Links to the subsequent page is found at the bottom of the page.

http://onlineappsdba.com/index.php/2008/07/22/oracle-weblogic-installation-steps/

More documentation on Weblogic is found here.

The documentation for creating a domain is found here.

Here is an overview about domains within WebLogic.

Friday, September 25, 2009

Daemonize a process in Unix

In unix when we run a command, it will usually run in the foreground and take over our terminal.

For long running processes, we can add & to create a child process to run the background. This will allow you to continue to use the terminal while waiting for the process to finish. However, for that process is still tied to the parent process and will terminate if you exit from your terminal.

Sometimes we want to start a process and let it continue to run even after we exit out of our terminal. This can be done using the nohup command.

For example, if we want to start the WebLogic server and have it continue serving out our web application even after we log out of the server. To do that just type:

nohup ./startWebLogic.sh &

All output will be redirected to a file called nohup.out but the WebLogic server process will continue to run even after we have logged out of the server.

Friday, September 18, 2009

Sun companion CD

The sun companion CD contains many useful software and is listed here.

Thursday, September 17, 2009

Installing WebLogic server on Sun Solaris x86

In order to install Weblogic server on Sun Solaris x86, you need to first upgrade the JDK to at least version 1.6. The instruction on how to do that is found here.

Sun Solaris u6 still has JDK version 1.5.

Next download the generic installer from the Oracle website.

To install go to the folder than contains the jar file downloaded (in this example server103_generic.jar and type:

java -jar server103_generic.jar

You can actually decide where you want to install it. By default, it will attempt to install it in /usr/local/bea folder.

In order to install the Workshop, you need to have Eclipse and WTP. I have not successfully done that so far. I tried to use the base Eclipse 3.5 but it still won't let me install. So I excluded that in my test installation.

After install, if you want access the console, you need to first start the server. This is found under:

/usr/local/bea/wlserver_10.3/samples/domains/wl_server/bin

Just type

./startWeblogic.sh

add & if you don't want to lock up your terminal. You can then access the console using

http://localhost:7001

You can then click on Start Administration Console to initiate and get into the Console.

Tuesday, September 15, 2009

Upgrading JDK in Sun Solaris

First go to Javasoft to download the software. In this example, I will use the j2se version 6 for Solaris x86. After you confirm all the selection, you have an option to select from 2 versions, one is .sh another is .Z. You only need the .sh version (which only contains the binaries).

The various versions Java is stored in /usr/jdk folder.

After downloading the .sh file to your folder run the following:

chmod +x jdk-6-solaris-i586.sh

to make the file executable.

change to root, then change directory to /usr/jdk

After that, run the script. so assuming the file is in /export/home/strovek/, type

/export/home/strovek/jdk-6u16-solaris-i586.sh

This will extract the every to the folder, in this case to /usr/jdk/jdk1.6.0_16

Then remove the existing symbolic link /usr/java and replace it with the new link

Just type:

ln -s jdk/jdk1.6.0_16 /usr/java

To verify, just type

java -version


Note that there is already symbolic link in /usr/sbin for java, javac etc that points to /usr/java.

Wednesday, September 9, 2009

Monday, August 24, 2009

Restricting Login times

The article on how to restrict logon time for XP is found here.

Snippet is as follows:

To add a new account type: net user "account name" /ADD * (do not use the quotes). The asterisk is to prompt you to provide the password for the account.

Using "net user" solitary, with no parameters, you will get the list with all the users on the computer. To delete an account, just use the syntax with /DELETE parameter:

net user TEST /Delete

How to configure logon hours for a user

Now that you are familiarized with the command, it's time to learn how to add parameters in order to limit logon access for a time interval.

Let's suppose the account for which we want to define the time interval access already exists. The command will look like this:

net user "user account" /time:M-F,14:00-16:00

Replace the text between the quotes with the desired account. Using the above command line, the user has rights to access its account between 14 and 17 every day from Monday to Friday. In case your son/daughter comes home from school around two o'clock he/she will be able to logon until 16 o'clock (when you come back from work).

Please notice that only sharp values are accepted. You can choose any hour but not subdivisions like 14:15 or 15:36.

You can even setup time intervals for different days as following:

net user softpedia /time:W,10am-5pm;T,2pm-3pm;F-Sa,9:00-16:00

One more thing, the week days' abbreviations are M, T, W, Th, F, Sa, Su.

Information on how to do it for Windows Vista is found here. Much easier since it is all GUI.

Friday, August 21, 2009

Learning Oracle - good website

Just found the following blog which contains a very rich information on how to manage Oracle:

http://msutic.blogspot.com/

Saturday, August 1, 2009

Converting MP4 to MPEG/AVI

Recently, I started taking videos using my handphone (PDA Phone). Videos taken using the phone defaults to MP4 format. However, I faced a problem of not being able to use Windows MovieMaker to edit and join the videos together.

I downloaded a few free video editor programs but most of them do not support MP4 format either. Finally, I came across Pazera Free MP4 to AVI converter which allows you to convert to MPEG-1 - which can then be used in Windows Movie Maker.

Wednesday, July 22, 2009

Friday, July 17, 2009

A short PL/SQL Course

Application Structure

The basic structure of a PL/SQL program consist of three parts:

Declare
...
Begin
...
End;

Using PL/SQL, we can develop several different kinds of codes:
  1. PL/SQL script. Codes that execute using external files.
  2. Database stored codes - once executed the code is stored in the database. This code consist several types:
  • Stored function (returns one value)
  • Stored procedure (does not return value - except through the parameter).
  • Triggers (linked to a specific action to a table.
Stored procedures and functions can be grouped together into a package.

For the code below, we will create a sample table called EmployeeTab as follows:

CREATE TABLE EMPLOYEETAB
(
ENO VARCHAR2(20),
ENAME VARCHAR2(40),
EDEPT VARCHAR2(20),
SUPNO VARCHAR2(20),
PHONE VARCHAR2(20),
JTITLE VARCHAR2(20)
);


CREATE TABLE EMPLOYEETABHIST
( ENO VARCHAR2(20 BYTE),
COLNAME VARCHAR2(20 BYTE),
OLDVAL VARCHAR2(40 BYTE),
NEWVAL VARCHAR2(40 BYTE),
CHANGEDATE DATE
);



Stored Procedure/Function

To create a stored procedure, the syntax is as follows:

Create or replace procedure storeData
/*
Sample stored procedure to store Employee Data
Author Strovek
Date Jul 17, 2009
*/
(pEno IN Varchar2,
pEName In Varchar2)
IS
Begin -- start of code
-- Insertion code here
Insert into EmployeeTab (eNo, eName) Values (pEno, pEName);

End storeData;


Note the code above:
  1. The code above takes in two parameters and both are input parameters.
  2. PL/SQL codes are not case sensitive so pEno and peno are the same.
  3. Comments can be added any where either surrounded by /* ... */ or -- (codes after -- is comment until the end of the line. while everything between the * are all comments irrespective of the number of lines.
Here is an example of a function which sums two parameters entered to it.
Create or Replace
Function sumFunc
(pVar1 IN Number, pVar2 IN Number)
Return Number IS
tmpNum Number;
Begin
tmpNum := pVar1 + pVar2;
return tmpNum;
End sumFunc;

Note the code above:
  1. Both parameter above are input parameters and in this example both are of type Number.
  2. This function will return a value of type number.
  3. After the keyword IS, we can declare our variables (this represent the Declare portion of the PL/SQL block.
  4. I used a parameter to return the value just to show how the local variables can be used. The code could be changed as follows:

Create or Replace
Function sumFunc
(pVar1 IN Number, pVar2 IN Number)
Return Number IS
Begin
return pvar1 + pvar2;
End sumFunc;

One nice thing about functions, is you can call the function as another column in your SQL statement. For example:

Select eNo, eName, sumFunc(5, 3) Age from EmployeeTab;


Package

Package allows the developer to group codes that are related together. So assuming that the above codes are common than we can group them together in a package. Package consist of two parts:
  1. Declaration
  2. Body
The declaration is as follows:

create or replace PACKAGE TestPack
AS
procedure storeData
/*
Sample stored procedure to store Employee Data
Author Strovek
Date Jul 17, 2009
*/
(pEno IN Varchar2,
pEName In Varchar2);
-------------
Function sumFunc
(pVar1 IN Number, pVar2 IN Number)
Return Number;
-------------
End TestPack;


The body contains the actual codes and the header needs to match the declaration as follows:

create or replace
PACKAGE BODY TestPack
AS
procedure storeData
/*
Sample stored procedure to store Employee Data
Author Strovek
Date Jul 17, 2009
*/
(pEno IN Varchar2,
pEName In Varchar2)
IS
Begin -- start of code
-- Insertion code here
Insert into EmployeeTab (eNo, eName) Values (pEno, pEName);

End storeData;
------------------
Function sumFunc
(pVar1 IN Number, pVar2 IN Number)
Return Number IS
tmpNum Number;
Begin
tmpNum := pVar1 + pVar2;
return tmpNum;
End sumFunc;

End TestPack;


To use the codes in the package, we need to prefix the procedure or function with the package name, for example:

Select eNo, eName, TestPack.sumFunc(5, 3) Age from EmployeeTab;

Triggers

Triggers are special type of stored procedures that will be executed based on an event. For example, in the case of the employeeTab, I would like to keep track of changes to the columns in the table. For this example, I make an assumption that eNo is the primary key and will not change. All changes will be stored in the EmployeeTabHist.

create or replace
Trigger trEmp_AttribUpd
Before Update Of eName, eDept, SupNo, Phone, jTitle on EmployeeTab
For Each Row
Declare
/*
Create a history of the changes in the employee attributes
Author Strovek
Date Jul 18, 2009
Revised
*/
Procedure ins_empattribhist(pParam IN Varchar2, pOldVal IN Varchar2, pNewVal IN Varchar2)
IS
Begin
insert into employeetabhist
(eNo, colName, oldVal, newVal, changedate) values
(:new.eNo, pParam, pOldVal, pnewVal, sysdate);

End ins_empattribhist;

Begin
If :old.eName <> :new.eName Then
ins_empattribhist('Name', :old.eName, :new.eName);
End If;
If :old.eDept <> :new.eDept Then
ins_empattribhist('Dept', :old.eDept, :new.eDept);
End If;
If :old.SupNo <> :new.SupNo Then
ins_empattribhist('SuperVisor', :old.SupNo, :new.SupNo);
End If;
If :old.Phone <> :new.Phone Then
ins_empattribhist('Phone', :old.Phone, :new.Phone);
End If;
If :old.jTitle <> :new.jTitle Then
ins_empattribhist('Name', :old.jTitle, :new.jTitle);
End If;

End;


Note the code above:
  1. Since some of the codes are common, we can reduce the amount of codes written by create a procedure within the trigger. This procedure is only accessible by the trigger since it is within the declaration section of the code.
  2. Some common columns can be obtained directly and does not need to passed to the code via parameters (e.g. eNo, which is the same irrespective of the attribute changed and the changedate which is the sysdate).
Error Handling

Similar to Java and Vb.Net, you can also catch and throw exceptions in PL/SQL. Before we go into that note that it is possible to create your own error code, Oracle has reserved the numbers -20000 to -20999 for this purpose.

Going back to the first section, we have the code block:

Declare
...
Begin
...
End;
There is an optional section between Begin and End called Exception. So the code can as follows:

Declare
...
Begin
...
Exception
...
End;

Similar to the try catch, you can specify multiple whens to handle different error codes. Some examples found here.

Using an earlier example of store data, we can further enhance it to prevent insertion of existing ENo as follows:

Create or replace procedure storeData2
/*
Sample stored procedure to store Employee Data
Author Strovek
Date Jul 17, 2009
*/
(pEno IN Varchar2,
pEName In Varchar2)
IS
Cursor chkRec IS
Select eName from employeeTab where eNo = pENo;
vChkRec chkRec%ROWTYPE;
vRecExist Boolean;

Begin -- start of code
vRecExist := False;
Open chkRec;
Fetch chkRec INTO vChkRec;
If chkRec%NOTFOUND Then
Insert into EmployeeTab (eNo, eName) Values (pEno, pEName);
Else
vRecExist := True;
End If;
Close chkRec;

If vRecExist Then
Raise_application_error(-20101, 'Eno ' || pENo || ' already exist, cannot insert record');
End If;

End storeData2;



Cursors

In order to retrieve records from a database via the sql statement, a cursor is used. The cursor can either be used implicitly or explicitly.

Implicit means that Oracle will open, fetch the records and close the cursor for you automatically.

An example of implicit cursor is as follows:

Set serveroutput on size 100000
Declare
cursor cGetEmp IS
Select eName, Phone from EmployeeTab;

Begin
For vRec in cGetEmp Loop
dbms_output.put_line(vRec.eName || ' phone number is ' || vRec.Phone);
End Loop;
End;


Note on the code above:
  1. I did not have to declare vRec. It is implied.
  2. I did not have to open the cursor. The records are fetched into vRec and once all the records are retrieve, the cursor is closed.
By comparison of an explicit cursor is as follows:

Set serveroutput on size 100000
Declare
cursor cGetEmp IS
Select eName, Phone from EmployeeTab;
vGetEmp cGetEmp%ROWTYPE;

Begin
Open cGetEmp;
Fetch cGetEmp INTO vGetEmp;
While cGetEmp%FOUND
Loop
dbms_output.put_line(vGetEmp.eName || ' phone number is ' || vGetEmp.Phone);
Fetch cGetEmp INTO vGetEmp;
End Loop;
Close cGetEmp;
End;


Note on the code above:
  1. vGetEmp had to be declared and to ease things, we use a special type called %ROWTYPE so the record type is changed depending on the cursor declaration.
  2. The cursor has to be opened and closed using the Open and Close statement.
  3. Each record has be fetched and we have to check for the end of the records using %FOUND condition.
Closing

This short cause is meant to only introduce you to PL/SQL programming and not meant to be comprehensive. Note that when writing to code to avoid using reserved words for variables. You can learn more about the Loops structure, logic, predefined function from the Oracle Manual.

Here is the one for Oracle 9i from Oracle.

When writing code, you can use Oracle SQL Developer (a freeware from Oracle) to write the codes. That way during compilation (especially for stored procedure/function/packages), you can easily find the cause why your code has error.

Any comments are welcome.

Wednesday, July 8, 2009

Source for Sudo

To download sudo for Solaris, this is the source:


http://www.courtesan.com/sudo/download.html

Excerpt from the following site, on what is sudo:


sudo stands for "su do", and means "do something as the supervisor". `sudo` is an enhanced alternative to the Unix `su` command.

The `su` command allows any user to obtain superuser privileges, if they know the root password:
bash-2.05a$ su -
Password:
#

The Impact of sudo on Unix System Security
`sudo` improves on `su` in several ways:
`sudo` allows you to give privileged access to only some commands, instead of all commands.
`sudo` allows you to log all commands (and their arguments) executed as the privileged user.
`sudo` does not require the administrator to share the root password.
`sudo` allows you to limit the users who can use it by editing the sudoers file.
`sudo` times out after 5 minutes (by default).