C (and C++) Code v. 1.2

Description

This program will read the input from an HTML form. After processing the form values, it will set up an SSL session to forward the values to the USA ePay gateway. Response from the gateway is then saved in a string variable resultStatus. Detailed descriptions and instructions can be found by going through the source code and reading the comments.

Requirements and Installation Instructions

The most important element in this program is the W3c's libwww library. It can be found online at http://www.w3.com/Library. This library is used to communicate with the gateway, post results and retrieve responses. To ensure a secure transaction, you also need to install OpenSSL. It also uses a module transport wrapper so that libwww can use SSL by Olga Antropova http://www.w3.org/Library/src/SSL/WWWSSL.html.

It is highly recommended that you install OpenSSL first and then configure libwww to use OpenSSL, before compiling and installing libwww. If you are using a current version of Linux distro such as Red Hat 7 or Mandrake 8, OpenSSL and libwww can be found in the Cds RPM packages. We recommended using these RPMs, as long as you don't mind using a generic build. More advanced developers may want to download the most current source and compile it themselves. The SSL wrapper should come with libwww. The program will work with both Windows and Linux operating systems.

If you are using Windows (and do not have libwww already installed) it would be easier to use Microsoft's WinInet. You can find a detailed description of WinInet and its functions from Microsoft's MSDN http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wininet/wininet/wininet_functions.asp If you decide to use WinInet, you will need libwww but it is not designed for WinInet (to use winInet you will need to write another program).

Optional

The program uses a cgi library called cgi-html by Noel V Aguilar found at http://www.geocities.com/SiliconValley/Vista/6493/projects/cgi-lib.html. It was used to facilitate the parsing and usage of form variables. You are not required to use this library, since you may have a library of your own that you prefer. The most important parts of this application are the libwww functions which show you how to set up and use an SSL session. If you choose not to use cgi-html, you will need to manually erase or "comment out" the following library functions:

  1. mime_header("text/html");
  2. LIST *head;
  3. head = cgi_input_parse();
  4. html_begin("C USAePay Gateway connect",NULL);
  5. find_val(head, "formVariable")
  6. html_end();

Compiling the Program

Compiling under Windows should be easy and straightforward using a compiler such as Visual C++. Remember to include you libwww Object/Library path in Project Settings->Link tab.

To compile under Linux, using gcc for example, you will need to point to the library paths during compilation. To compile with libwww, SSL and cgi-html you would need to type something similar to:

gcc -o "yourCGIFileName.cgi" libwww-config --cflags yourSourceFile.c libwww-config --libs -L/usr/lib -lwwwssl /path/to/cgi-html/library/cgi-lib.a

This is assuming you installed libwww in /usr/lib.

To install without cgi-html, all you need to do is take out the path at the end of the command: gcc -o "yourCGIFileName.cgi" libwww-config --cflags yourSourceFile.c libwww-config --libs -L/usr/lib -lwwwssl It would be a good idea to run the commands: libwww-config --cflags & libwww-config --libs before compiling, to see the exact path of your libwww and the modules installed. If you can find the SSL wrapper -lwwwssl in the list, then you won't need to add the -L/usr/lib -lwwwssl at the end.

Running the Program

Copy the compiled file into your website's cgi folder. Remember to make sure the permissions are set up correctly. On Linux you will need to change chgrp and chown to a username that can run cgi files, also make sure to chmod to 755.

Warning

Use an HTML form with the action pointing to the cgi file. If you run the program without any form fields sent through either GET or POST you will probably receive an "Internal Server Error." This is because cgi-html will output an error message that there are no form fields, before outputting a content-type, which is necessary for normal http operation. You can circumvent this error by adding an "if" statement to check if there is a QUERY_STRING and if the CONTENT_LENGTH is greater than zero in the environment variables. Then execute the command head = cgi_input_parse(); or else print your own error message with a proper content-type.

Example Code

    /*Code for libwwwPost.c
    /*Written by min2web for USAEpay
    for questions or comments you can contact us at:
    support@usaepay.com
    OR
    mind2webinfo@yahoo.com

    */
    /*this program requires libwww libraries found at
    http://www.w3.org/Library
    to contact and submit info to the server.
    You will also need to have the SSL wrapper for libwww wwwssl.*/
    #include "WWWLib.h"
    #include "WWWHTTP.h"
    #include "WWWInit.h"
    #include "WWWSSL.h"
    #include `<stdio.h>`
    #include `<stdlib.h>`
    /*In this program we are using the ANSI C library cgi-html by Noel V Aguilar
    found at
    http://www.geocities.com/SiliconValley/Vista/6493/projects/cgi-lib.html
    It is not necessary to use this library. You can simply replace it with your
    own form parsing function.*/
    #include "cgi-lib/cgi-lib.h" /* include the cgi-lib.h header file THIS SHOULD BE
    THE PATH TO THE cgi-html LIBRARY */
    #include "cgi-lib/html-lib.h" /* include the html-lib.h header file THIS SHOULD
    BE THE PATH TO THE cgi-html LIBRARY */
    /*as mentioned above you are not required to use the cgi-html
    library, it is only used in this program to facilitate the form
    processing functions. The main focus of the program is the libwww
    functions*/

    //we set a variable of type HTChunk that will eventually contain the server response.
    PRIVATE HTChunk * result = NULL;
    char resultStatus[1000];

    //The following two functions tell libwww what to do in case of
    //messages and trace. We will see these set as callback functions later on
    PRIVATE int printer (const char * fmt, va_list pArgs)
    {
    return (vfprintf(stdout, fmt, pArgs));
    }

    PRIVATE int tracer (const char * fmt, va_list pArgs)
    {
    return (vfprintf(stderr, fmt, pArgs));
    }

    //The following function describes what to do when libwww's main
    //event loop terminates. That is after libwww has contacted the
    //server and has recieved the result. This is where you might like
    //to add your own response handling function.
    PRIVATE int terminate_handler (HTRequest * request, HTResponse * response,
    void *param, int status)
    {
    if (status == HT_LOADED && result && HTChunk_data(result)) {
    //HTPrint("%s", HTChunk_data(result));
    sprintf(resultStatus, "%s", HTChunk_data(result));
    printf("\nresultStatus = %s", resultStatus);
    /*Results are saved in string resultStatus. For further validation comment out the
    above printf code,
    instead put your own URLdecoding function to decode the server's response and
    display it to your users.*/
    HTChunk_delete(result);
    }

    /* We are done with this request */
    HTRequest_delete(request);

    HTSSLhttps_terminate();

    /* Terminate libwww */
    HTProfile_delete();

    exit(status ? status : 0);
    }


    int main (int argc, char ** argv)
    {
    HTRequest * request = NULL;
    HTAnchor * anchor = NULL;
    HTAssocList * formfields = NULL;
    char * uri = "https://www.usaepay.com/gate.php";

    //Initiate CGI session. This is from cgi-html
    mime_header("text/html");

    //LIST that cgi-html uses.
    LIST *head;

    //parse form variables. cgi-html
    head = cgi_input_parse();

    //print HTML header. cgi-html
    html_begin("C USAePay Gateway connect",NULL);
    printf("`<pre>`\n");

    char string[10000];

    //The following "if" statements determine if the required fields are found
    sprintf(string, "%s", find_val(head, "UMkey"));

    //find_val is a cgi-html function that returns the value of the form key.
    if (find_val(head, "UMkey") == NULL || strcmp(string, "") == 0)
    {
    printf("`<center>``<h1>`ERROR`</h1>``<br>`Source Key not found. Cannot complete
    operation.");
    html_end();
    return 0;
    }

    if ((find_val(head, "UMcard") != NULL && find_val(head, "UMexpir") != NULL)
    ||
    (find_val(head, "UMrouting") != NULL && find_val(head, "UMaccount") !=
    NULL
    && find_val(head, "UMssn") != NULL && find_val(head, "UMdlnum") != NULL
    && find_val(head, "UMdlstate") != NULL))
    {
    if (find_val(head, "UMamount") == NULL ||
    find_val(head, "UMinvoice") == NULL ||
    find_val(head, "UMname") == NULL ||
    find_val(head, "UMstreet") == NULL ||
    find_val(head, "UMzip") == NULL )
    {
    printf("`<center>``<h1>`ERROR`</h1>``<br>`Missing form fields.`<br>`Please click the
    back button and complete all required fields.`<br>` Cannot complete operation.");
    html_end();
    return 0;
    }
    }
    else
    {
    printf("`<center>``<h1>`ERROR`</h1>``<br>`Missing form fields.`<br>`Please click the
    back button and complete all required fields.`<br>` Cannot complete operation.");
    html_end();
    return 0;
    }

    //Initiate SSL wrapper for libwww
    /* Create a new preemptive client */
    HTProfile_newNoCacheClient("TestApp", "1.0");

    HTSSL_protMethod_set (HTSSL_V23);

    HTSSL_verifyDepth_set (2);
    //Be careful of the following init statement. If set to YES it could
    //initiate a blocking session. Currently it is set to NO to have a
    //non-blocking https communication. If you have problems receiving a
    //response from the server, you may want to try setting the value to YES.
    HTSSLhttps_init(NO);

    /* Need your own trace and print functions */
    HTPrint_setCallback(printer);
    HTTrace_setCallback(tracer);

    /* Get trace messages, change the 0 to 1 to see more detailed trace
    message*/
    #if 0
    HTSetTraceMessageMask("sop");
    #endif

    /* Add our own filter to update the history list */
    HTNet_addAfter(terminate_handler, NULL, NULL, HT_ALL, HT_FILTER_LAST);

    /* Set the timeout to how long we will wait for a response */
    HTHost_setEventTimeout(10000);


    /* Create a list to hold the form arguments */
    if (!formfields) formfields = HTAssocList_new();

    /* Parse the content and add it to the association list */
    /*you can add as many more fields as you want here*/
    sprintf(string, "UMkey=%s", find_val(head, "UMkey"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMauthCode=%s", find_val(head, "UMauthCode"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMrefNum=%s", find_val(head, "UMrefNum"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMcard=%s", find_val(head, "UMcard"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMexpir=%s", find_val(head, "UMexpir"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMrouting=%s", find_val(head, "UMrouting"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMaccount=%s", find_val(head, "UMaccount"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMamount=%s", find_val(head, "UMamount"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMtax=%s", find_val(head, "UMtax"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMcustid=%s", find_val(head, "UMcustid"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMinvoice=%s", find_val(head, "UMinvoice"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMponum=%s", find_val(head, "UMponum"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMticket=%s", find_val(head, "UMticket"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMdescription=%s", find_val(head, "UMdescription"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMcvv2=%s", find_val(head, "UMcvv2"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMcustemail=%s", find_val(head, "UMcustemail"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMcustreceipt=%s", find_val(head, "UMcustreceipt"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMname=%s", find_val(head, "UMname"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMstreet=%s", find_val(head, "UMstreet"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMzip=%s", find_val(head, "UMzip"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMssn=%s", find_val(head, "UMssn"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMdlnum=%s", find_val(head, "UMdlnum"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMdlstate=%s", find_val(head, "UMdlstate"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMip=%s", find_val(head, "UMip"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMcommand=%s", find_val(head, "UMcommand"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMredir=%s", find_val(head, "UMredir"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMredirApproved=%s", find_val(head, "UMredirApproved"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMredirDeclined=%s", find_val(head, "UMredirDeclined"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMechofields=%s", find_val(head, "UMechofields"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMechounsafe=%s", find_val(head, "UMechounsafe"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMtestmode=%s", find_val(head, "UMtestmode"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMrecurring=%s", find_val(head, "UMrecurring"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMschedule=%s", find_val(head, "UMschedule"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMnumleft=%s", find_val(head, "UMnumleft"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMstart=%s", find_val(head, "UMstart"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMemail=%s", find_val(head, "UMemail"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMbillfname=%s", find_val(head, "UMbillfname"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMbilllname=%s", find_val(head, "UMbilllname"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMbillcompany=%s", find_val(head, "UMbillcompany"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMbillstreet=%s", find_val(head, "UMbillstreet"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMbillstreet2=%s", find_val(head, "UMbillstreet2"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMbillcity=%s", find_val(head, "UMbillcity"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMbillstate=%s", find_val(head, "UMbillstate"));
    HTParseFormInput(formfields, string);
    sprintf(string, "umbillzip=%s", find_val(head, "UMbillzip"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMbillcountry=%s", find_val(head, "UMbillcountry"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMbillphone=%s", find_val(head, "UMbillphone"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMemail=%s", find_val(head, "UMemail"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMfax=%s", find_val(head, "UMfax"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMwebsite=%s", find_val(head, "UMwebsite"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMshipfname=%s", find_val(head, "UMshipfname"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMshiplname=%s", find_val(head, "UMshiplname"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMshipcompany=%s", find_val(head, "UMshipcompany"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMshipstreet=%s", find_val(head, "UMshipstreet"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMshipstreet2=%s", find_val(head, "UMshipstreet2"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMshipcity=%s", find_val(head, "UMshipcity"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMshipstate=%s", find_val(head, "UMshipstate"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMshipzip=%s", find_val(head, "UMshipzip"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMshipcountry=%s", find_val(head, "UMshipcountry"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMshipphone=%s", find_val(head, "UMshipphone"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMcardauth=%s", find_val(head, "UMcardauth"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMpares=%s", find_val(head, "UMpares"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMxid=%s", find_val(head, "UMxid"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMcavv=%s", find_val(head, "UMcavv"));
    HTParseFormInput(formfields, string);
    sprintf(string, "UMeci=%s", find_val(head, "UMeci"));
    HTParseFormInput(formfields, string);



    if (uri && formfields) {

    /* Create a request */
    request = HTRequest_new();

    /* Set the default output to "asis" */
    HTRequest_setOutputFormat(request, WWW_SOURCE);

    /* Get an anchor object for the URI */
    anchor = HTAnchor_findAddress(uri);

    /* Post the data and get the result in a chunk */
    result = HTPostFormAnchorToChunk(formfields, anchor, request);

    /* Clean up the form fields */
    HTAssocList_delete(formfields);

    /* Go into the event loop... */
    HTEventList_loop(request);

    } else {
    printf("`<center>``<h1>`ERROR`</h1>``<br>`Missing form fields.`<br>`Please click the
    back button and complete all required fields.`<br>` Cannot complete operation.");
    html_end();
    return 0;
    }

    printf("`</pre>`\n");
    html_end();
    return 0;
    }

Example HTML FORM Code

    <html>
    <head>
        <title>Credit Card sample form</title>
    </head>

    <body>

    <form action="path/to/your/cgi/folder/yourCGIexecutable.cgi" method="POST">
    <input type="hidden" name="UMkey" value="YOUR_SOURCE_KEY_HERE">
    <table border="1" width="80%">
    <tr>
    <td>Card Number</td>
    <td><input type="text" name="UMcard" size="12"></td>
    </tr>
    <tr>
    <td>Expire Date (MM/YY)</td>
    <td><input type="text" name="UMexpirM" size="2" maxlength="2">/
    <input type="text" name="UMexpirY" size="2" maxlength="2"></td>
    </tr>
    <tr>
    <td>Amount</td>
    <td>$<input type="text" name="UMamount" size="6"></td>
    </tr>
    <tr>
    <td>Invoice Number</td>
    <td><input type="text" name="UMinvoice" size="12"></td>
    </tr>
    <tr>
    <td>Customer Name</td>
    <td><input type="text" name="UMname" size="20"></td>
    </tr>
    <tr>
    <td>Street</td>
    <td><input type="text" name="UMstreet" size="20"></td>
    </tr>
    <tr>
    <td>Zip</td>
    <td><input type="text" name="UMzip" size="5" maxlength="5"></td>
    </tr>
    <tr>
    <td align="center"><input type="submit" name="submit" value="Submit"></td>
    <td align="center"><input type="reset" name="reset" value="reset"></td>
    </tr>
    </table>
    </form>

    </body>
    </html>

Change Log

1.0.1 -> 1.2 Added support for VBV and MSC as well as other fields (tax, po...). 10/15/03