Secure Login
C

We offer code samples to make it easy for you to plug in SMS functionality into your applications.

Download our SDK containing sample projects in many languages or go straight to the language you need with our code samples.

/* #define WINDOWS */

#define UNIX

#include <stdio.h>
#include <stdlib.h>

#ifdef WINDOWS
#include <winsock.h>
#endif

#ifdef UNIX

#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>

typedef int BOOL;

#define FALSE 0
#define TRUE 1

#define SOCKET int

#define SUCCESS 0
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1

#endif

/* Define some useful constants. */

static const char NULLCHAR = '\0';

static const char CR = '\r';
static const char LF = '\n';

static const char *CRLF = "\r\n";

static const int NO_FLAGS = 0;

/* Generic character string data with its metadata. */

typedef struct _String
{
    int size;
    char *value;
    void (*append)(struct _String *string1, const char *string2, const int size);
}
String;

/* 2sms account user login credentials. */

typedef struct _Credentials
{
    String username;
    String password;
}
Credentials;

/* Parameters for a SendMessage request. */

typedef struct _SendMessageArgs
{
    Credentials credentials;
    String destination;
    String message;
    String response;
}
SendMessageArgs;

/* Specify what action to take with this request. */
/* SEND actually submits the request for processing. */
/* VALIDATE just returns the schema validation results. */

typedef enum _RequestAction
{
    ACTION_SUBMIT = 0,
    ACTION_VALIDATE = 1
}
RequestAction;

void append(String *string1, const char *string2, const int size)
{
    string1->size += size;
    string1->value = realloc(string1->value, (string1->size + 1) * sizeof(char));
    strncat(string1->value, string2, size);

    return;
}

/*
* Send the specified request, encoded with the specified MIME content
* type, to the specified target on the specified host using HTTP.
*/
int sendHttp(const char *host, const char *target, const char *request, const char *mime, String *response)
{
    /* HTTP request and response header templates. */
    const char *HTTP_ACTION_TEMPLATE = "POST %s HTTP/1.1\r\n";
    const char *HTTP_HOST_TEMPLATE = "Host: %s\r\n";
    const char *HTTP_CONTENT_LENGTH_TEMPLATE = "Content-Length: %d\r\n";
    const char *HTTP_CONTENT_TYPE_TEMPLATE = "Content-Type: %s\r\n";
    const char *HTTP_RESPONSE_TEMPLATE = "HTTP/1.1 %d";
    const char *HTTP_CONTENT_SEPARATOR = "\r\n\r\n";

    /* HTTP response code indicating success. */
    const int HTTP_SUCCESS = 200;

    /* HTTP default TCP/IP port. */
    const int HTTP_DEFAULT_PORT = 80;

    /* The space to allocate for reading and writing remote server data. */
    const int BUFFER_SIZE = 1024;

    /* Socket library input socket and host data definitions. */
    struct sockaddr_in sin;
    struct hostent *hostAddr = NULL;

    /* Work buffer for reading and writing remote server data. */
    char *buffer = NULL;

    /* Pointer to the content following the header. */
    char *content = NULL;

    /* Count of the number of characters successfully read. */
    int readCount = 0;

    /* HTTP response code. */
    int code = 0;

    /* Socket handle. */
    SOCKET sock = 0;

    /* Flag to show if the header has been processed. */
    BOOL header = FALSE;

    /* Return code sent back to the calling process. */
    int ret = SUCCESS;

    /* Create a raw TCP/IP stream socket on this host. */
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    /* Check that a valid socket handle was returned. */
    if (sock == INVALID_SOCKET)
        ret = INVALID_SOCKET;
    else
    {
        /* Configure the input socket settings. */
        /* The port is converted to big-endian TCP/IP byte order by htons. */
        sin.sin_family = AF_INET;
        sin.sin_port = htons(HTTP_DEFAULT_PORT);

        /* Look up the specified host name. */
        if ((hostAddr = gethostbyname(host)) == NULL)
        {
            printf("Cannot find the specified host\n");
            ret = SOCKET_ERROR;
        }
        else
        {
            /* Point the input socket at the specified host. */
            sin.sin_addr.s_addr = *((int *)*hostAddr->h_addr_list);

            /* Connect to the remote host. */
            if (connect(sock, (const struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
            {
                printf("Cannot connect to the specified host\n");
                ret = SOCKET_ERROR;
            }
            else
            {
                /* Allocate space to write out the request header data. */
                buffer = malloc((BUFFER_SIZE + 1) * sizeof(char));

                /* Format and send the HTTP action header to the remote host. */
                sprintf(buffer, HTTP_ACTION_TEMPLATE, target);
                send(sock, buffer, strlen(buffer), NO_FLAGS);

                /* Format and send the HTTP host header to the remote host. */
                sprintf(buffer, HTTP_HOST_TEMPLATE, host);
                send(sock, buffer, strlen(buffer), NO_FLAGS);

                /* Format and send the HTTP content type header to the remote host. */
                sprintf(buffer, HTTP_CONTENT_TYPE_TEMPLATE, mime);
                send(sock, buffer, strlen(buffer), NO_FLAGS);

                /* Format and send the HTTP content length header to the remote host. */
                sprintf(buffer, HTTP_CONTENT_LENGTH_TEMPLATE, strlen(request));
                send(sock, buffer, strlen(buffer), NO_FLAGS);

                /* Format and send the HTTP request, correctly spaced, to the remote host. */
                send(sock, CRLF, strlen(CRLF), NO_FLAGS);
                send(sock, request, strlen(request), NO_FLAGS);
                send(sock, CRLF, strlen(CRLF), NO_FLAGS);

                /* Read the HTTP response. */
                while (ret == SUCCESS && (readCount = recv(sock, buffer, BUFFER_SIZE, NO_FLAGS)) > 0)
                {
                    buffer[readCount] = NULLCHAR;

                    /* If there was a previous response packet, just append this one to its content. */
                    if (header)
                        response->append(response, buffer, readCount);
                    else
                    {
                        /* Extract the HTTP response code. */
                        sscanf(buffer, HTTP_RESPONSE_TEMPLATE, &code);

                        /* Check for a success code. */
                        if (code != HTTP_SUCCESS)
                            ret = SOCKET_ERROR;
                        else if ((content = strstr(buffer, HTTP_CONTENT_SEPARATOR)) != NULL)
                        {
                            /* Extract and store the first part of the response content. */
                            content += strlen(HTTP_CONTENT_SEPARATOR);
                            response->append(response, content, strlen(content));
                        }

                        /* Register the fact that we have found and parsed an HTTP header packet. */
                        header = TRUE;
                    }
                }

                /* Report any socket read error back to the caller. */
                if (readCount == SOCKET_ERROR)
                    ret = SOCKET_ERROR;

                /* Release memory allocated for socket reads. */
                free(buffer);
            }
        }
    }

    return(ret);
}

/*
* Send the specified XML request to the specified target on the specified host.
*/
int sendXml(const char *host, const char *target, const char *request, String *response)
{
    /* Declare the MIME type corresponding to XML formatted text content. */
    const char *MIME_XML = "text/xml";

    /* Delegate the actual sending to the generic HTTP send method. */
    return(sendHttp(host, target, request, MIME_XML, response));
}

/*
* Send the specified XML request to a 2sms server page appropriate to the specified action.
*/
const int sendRequest(const char *request, String *response, const RequestAction action)
{
    /* Declare the 2sms host name. */
    const char *HOST_2SMS = "www.2sms.com";

    /* Declare the 2sms URL for parsing and performing XML schema requests. */
    const char *PAGE_SEND = "/xml/xml.jsp";

    /* Declare the 2sms URL for parsing and validating XML schema requests. */
    const char *PAGE_VALIDATE= "/xml/validate.jsp";

    /* Delegate the actual sending to the generic XML send method. */
    return(sendXml(HOST_2SMS, action == ACTION_SUBMIT ? PAGE_SEND : PAGE_VALIDATE, request, response));
}

/*
* Send a 2sms XML schema 'send message' request containing the specified
* arguments to a 2sms server page appropriate to the specified action.
*/
const int sendMessage(SendMessageArgs *args, const RequestAction action)
{
    /* Declare a template for the XML schema 'send message' request. */
    const char *SEND_TEMPLATE =
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
        <Request xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://schema.2sms.com/2.0/schema/0410_RequestSendMessage.xsd\" Version=\"1.0\">\
            <Identification>\
                <UserID>%s</UserID>\
                <Password>%s</Password>\
            </Identification>\
            <Service>\
                <ServiceName>SendMessage</ServiceName>\
                <ServiceDetail>\
                    <SingleMessage>\
                        <Destination>%s</Destination>\
                        <Text>%s</Text>\
                    </SingleMessage>\
                </ServiceDetail>\
            </Service>\
        </Request>";

    /* Calculate the total length of the XML request string, with placeholders replaced. */
    const int size = strlen(SEND_TEMPLATE) +
        strlen(args->credentials.username.value) +
        strlen(args->credentials.password.value) +
        strlen(args->destination.value) +
        strlen(args->message.value);

    /* Allocate sufficient memory to contain the XML request string. */
    char *request = malloc((size + 1) * sizeof(char));

    /* Initialise the code for return to the caller. */
    int ret = SUCCESS;

    /* Substitute the specified arguments for the XML request placeholders. */
    sprintf(request, SEND_TEMPLATE,
        args->credentials.username.value,
        args->credentials.password.value,
        args->destination.value,
        args->message.value);

    /* Delegate the actual sending to the generic XML request send method. */
    ret = sendRequest(request, &args->response, action);

    /* Release memory allocated for the XML request string. */
    free(request);

    return(ret);
}

/*
* Initialise the arguments required for a 'send message' request.
* Prompt the user for any required arguments that were not supplied.
*/
void getSendMessageArgs(const int argc, char *argv[], SendMessageArgs *args)
{
    /* The format of the user prompt for a missing argument. */
    const char *PROMPT_TEMPLATE = "Please enter the %s (with no spaces): ";

    /* The format of input data that is expected, i.e. a string of a specified maximum length. */
    const char *INPUT_TEMPLATE = "%%%ds";

    /* Declare the maximum allowable sizes of each string argument. */
    const int USERNAME_SIZE = 255;
    const int PASSWORD_SIZE = 255;
    const int DESTINATION_SIZE = 255;
    const int MESSAGE_SIZE = 255;
    const int RESPONSE_SIZE = 0;

    /* Associate descriptive strings with the memory location of each argument. */
    struct
    {
        const char *name;
        String *value;
    } arg[] =
    {
        { "2sms account username",    &args->credentials.username },
        { "2sms account password",    &args->credentials.password },
        { "destination phone number", &args->destination          },
        { "message to send",          &args->message              },
        { "response",                 &args->response             }
    };

    /* Buffer in which to form the required input data format specifier. */
    char format[10];

    /* Counter for the argument buffer allocation and population loops. */
    int i = 0;

    /* Initialise the length metadata for each argument. */
    args->credentials.username.size = USERNAME_SIZE;
    args->credentials.password.size = PASSWORD_SIZE;
    args->destination.size = DESTINATION_SIZE;
    args->message.size = MESSAGE_SIZE;
    args->response.size = RESPONSE_SIZE;

    /* For each argument... */
    for (i = 0; i < 5; i++)
    {
        /* Assign its append method. */
        arg[i].value->append = append;

        /* Allocate its memory according to its length metadata. */
        arg[i].value->value = malloc((arg[i].value->size + 1) * sizeof(char));

        /* Initialise the argument value. */
        *arg[i].value->value = NULLCHAR;
    }

    /* For each argument... */
    for (i = 0; i < 4; i++)
    {
        /* Copy any specified argument value. */
        if (argc > (i + 1))
            strcpy(arg[i].value->value, argv[i + 1]);
        else if (i < 3)        /* The fourth argument is optional. */
        {
            /* Prompt the user to supply the argument value. */
            printf(PROMPT_TEMPLATE, arg[i].name);

            /* Form the correct input data format specifier using its length metadata. */
            sprintf(format, INPUT_TEMPLATE, arg[i].value->size);

            /* Store the input argument value. */
            scanf(format, arg[i].value->value);
        }
    }

    /* Set a default message, if none was supplied. */
    if (strlen(arg[3].value->value) < 1)
        strcpy(arg[3].value->value, "Test message from 2sms.com");

    return;
}

/*
* Release memory allocated for the 'send message' request arguments.
*/
void freeSendMessageArgs(SendMessageArgs *args)
{
    free(args->credentials.username.value);
    free(args->credentials.password.value);
    free(args->destination.value);
    free(args->message.value);
    free(args->response.value);

    return;
}

/*
* Initialise the TCP/IP socket environment correctly for the target host system.
*/
void startup(void)
{
#ifdef WINDOWS
    WSADATA    data;
    WSAStartup(MAKEWORD(1, 1), &data);
#endif

    return;
}

/*
* Terminate the TCP/IP socket environment correctly for the target host system.
*/
void cleanup(void)
{
#ifdef WINDOWS
    WSACleanup();
#endif

    return;
}

/*
* Calling process entry point.
*/
int main(int argc, char *argv[])
{
    /* Initialise the status code for return to the calling process. */
    int ret = SUCCESS;

    /* Allocate memory for a set of 'send message' request arguments. */
    SendMessageArgs *args = malloc(1 * sizeof(SendMessageArgs));

    /* Initialise the 'send message' request arguments using any from the calling process. */
    getSendMessageArgs(argc, argv, args);

    /* Perform any environmental initialisation that is required. */
    startup();

    /* Perform the required action on the 'send message' request: */

    /* Validate the 'send message' request document against the relevant XML schema. */
/*    ret = sendMessage(args, ACTION_VALIDATE); */

    /* Send the message. */
    ret = sendMessage(args, ACTION_SUBMIT);

    /* Display the result of the above action to the standard output stream. */
/*    printf(args->response.value); */

    /* Perform any environmental termination that is required. */
    cleanup();

    /* Release the memory allocated for the individual 'send message' arguments. */
    freeSendMessageArgs(args);

    /* Release the memory allocated for 'send message' arguments as a whole. */
    free(args);

    return(ret);
}
©2sms Business Text Messaging,2018