Main | December 2006 »

November 2006 Archives

November 25, 2006

ESMTP Class

By Brandon W. Yuille

Well, this is my first post on the PT Development Blog, so I thought I would start with some code that I know many will find useful.

This is a class I worte for a billing system to send out emails to customers when their invoices were ready to be viewed online.

Hope you'll be able to make use of this class!

Class Declaration

/**************************************************************

Name: ESMTP Class Ver: 1.0.1.1 Author: Brandon W. Yuille

Desc: This class assumes MFC is used and all socket
initializations have taken place in
CWinApp::InitInstance(). Please don't consider this code
as production code for any sort of SMTP client. This is
simply provided so you can acomplish some simple tasks.
If you make modifications to this code that are useful,
please share them with others!

This class is free to use by anyone.

Copyright (C) 2006 Photon Technologies
**************************************************************/
#pragma once

#include <vector>

class CESMTP
{
public:
CESMTP(void);
~CESMTP(void);

void AddRecipient(CString address, CString name = "");
void SetFrom(CString address, CString name = "");
void SetSubject(CString subject);
void SetESMTPServerAddress(CString address);
void SetESMTPServerPort(int port = 25);
void SetMsgBody(CString data);

BOOL SendMsg();

protected:
BOOL RecvMessage(SOCKET *psock, CString requiredcode);

struct NAMEADDR
{
CString name;
CString addr;
};

std::vector<NAMEADDR> m_vto;
NAMEADDR m_from;
CString m_serveraddr;
int m_serverport;
CString m_data;
CString m_subject;
};


Class Implementation

#include "StdAfx.h"
#include ".\esmtp.h"

CESMTP::CESMTP(void)
{
m_serverport = 25;
}

CESMTP::~CESMTP(void)
{
}

void CESMTP::AddRecipient(CString address, CString name)
{
NAMEADDR na;
na.addr = address;
na.name = name;

m_vto.push_back(na);
}

void CESMTP::SetFrom(CString address, CString name)
{
m_from.addr = address;
m_from.name = name;
}

void CESMTP::SetSubject(CString subject)
{
m_subject = subject;
}

void CESMTP::SetESMTPServerAddress(CString address)
{
m_serveraddr = address;
}

void CESMTP::SetESMTPServerPort(int port)
{
m_serverport = port;
}

void CESMTP::SetMsgBody(CString data)
{
data.Replace("\r\n.\r\n", "\r\n..\r\n");
if(data.Left(3) == ".\r\n")
data.Insert(0, ".");

m_data = data;
}

BOOL CESMTP::SendMsg()
{
SOCKET sock;
SOCKADDR_IN saremote;
CString SendBuf;

// Create the TCP/IP CCCP socket.
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
return FALSE;
}

saremote.sin_family = AF_INET;
saremote.sin_port = htons((short)m_serverport);
if(inet_addr(m_serveraddr.GetString()) == INADDR_NONE)
{
HOSTENT *hp;
hp = gethostbyname(m_serveraddr.GetString());
saremote.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
}
else
{
saremote.sin_addr.s_addr = inet_addr(m_serveraddr.GetString());
}

// Connect to CCCP server.
if(connect(sock, (SOCKADDR*)&saremote, sizeof(saremote)) == SOCKET_ERROR)
{
return FALSE;
}

// Recieve Banner
if(!RecvMessage(&sock, "220"))
{
closesocket(sock);
return FALSE;
}

// Send EHLO
SendBuf = "EHLO\r\n";
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve OK
if(!RecvMessage(&sock, "250"))
{
closesocket(sock);
return FALSE;
}

// Send MAIL FROM:<address@domain.com>
SendBuf = "MAIL FROM:" + m_from.addr + "\r\n";
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve OK
if(!RecvMessage(&sock, "250"))
{
closesocket(sock);
return FALSE;
}

for(int i = 0; i < m_vto.size(); i++)
{
// Send RCPT TO:<address@domain.com>
SendBuf = "RCPT TO:" + m_vto.at(i).addr + "\r\n";
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve OK
if(!RecvMessage(&sock, "250"))
{
closesocket(sock);
return FALSE;
}
}

// Send DATA
SendBuf = "DATA\r\n";
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve Begin DATA
if(!RecvMessage(&sock, "354"))
{
closesocket(sock);
return FALSE;
}

CString MsgBody;
MsgBody += "Subject: " + m_subject + "\r\n";
MsgBody += "To: ";
for(int i = 0; i < m_vto.size(); i++)
{
MsgBody += " " + m_vto.at(i).name + " <" + m_vto.at(i).addr + ">;";
}
MsgBody += "\r\n\r\n";
// Add the message data
MsgBody += m_data;
// End the message
MsgBody += "\r\n.\r\n";

SendBuf = MsgBody;
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve OK
if(!RecvMessage(&sock, "250"))
{
closesocket(sock);
return FALSE;
}

SendBuf = "QUIT\r\n";
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve Connection Closed
if(!RecvMessage(&sock, "221"))
{
closesocket(sock);
return FALSE;
}

closesocket(sock);
return TRUE;
}

BOOL CESMTP::RecvMessage(SOCKET *psock, CString requiredcode)
{
char szBuf[1025];
CString Buffer;
CString MsgCode;
int BufLen = 0;
int icount = 0;

while((BufLen = recv(*psock, szBuf, 1024, 0)) > 0)
{
szBuf[BufLen] = '\0';
Buffer += szBuf;

if(icount == 0)
MsgCode = Buffer.Left(3);

if(Buffer.Find(MsgCode + " ") != -1)
break;

icount++;
}

if(MsgCode == requiredcode)
return TRUE;

return FALSE;
}

November 27, 2006

Introduction to Call Capture

By Brandon W. Yuille

At first glance Call Capture may seem to be just another caller id program (like the ones that listen on your modem port). This is completely incorrect! Call Capture is a complete management/contact suite that is built to work with the Cisco IP Telephony system (expecting future versions to handle any IP phones that use SIP). Ever wonder why you switched to your new VoIP phone system (besides the low cost)? Well, you’re about to find out.

When running Call Capture, when someone calls, you get a notification via a fade-in window on the bottom right of your desktop that informs you of the person's name/company and other information. At this point you have some options: add this person to your contact directory, wait until you are finished with your conversation to add them to the later by navigating to your call history (which is almost infinite in space), or if they are already a contact in your system you can bring up all contact information that has been previously entered (by a coworker, yourself, ect) simply by clicking a button (I bet that customer will be amazed that you already know the entire history of their problem as soon as you answer).

Hopefully by that last point you're noticing the power of this application; real time accessible data by anyone in your company! There’s never a chance to miss a lead because you were unable to locate the contact’s information from Bob before he went home. Now you know everything Bob, John, Shirley, ect know when they know it.

Chances are, if you are reading this, you are involved in managing other employees. If so, then you know how important it is for them to gather as much information as possible on every single person who calls your company. Generally if someone calls you and you sell computers, they’re not looking to buy a car. That’s why every call you receive should be regarded as the best sales lead you’ll ever get! The problem lies in the fact that getting your employees to record this valuable information is almost impossible. Even if someone made a note of 2 inquiry calls chances are they are not telling you about the 30 they didn’t. Call Capture changes all this. Now you have an easy to use software suite linked in to all of your employees to view call history reports and other very useful information for determining the productivity of the individuals you are managing.

The Call Capture interface makes adding a contact about a 2 step process: when a person calls and they are not already in your contact list, you will be prompted with a new contact window to enter in some information about the person (don’t worry, we’ve implemented automatic name, company, and address information for you so you don’t have to bother with that). Then once you have all the information you need from the person, simply save their new contact window and instantly everyone in your company has access to this information. Now when you transfer this person over to tech support, they can bring up any and all information about this contact and the customer is saved from the annoyance of repeating themselves.

I’ve only tapped the surface of the Call Capture suite. As I said, this is only an introduction, but hopefully with the new knowledge of Call Capture you should have no more questions about why you bought that new phone system!

November 30, 2006

Recursively Enumerating the Files within a Directory and its Subdirectories

By Brandon W. Yuille

I want to share a function that is very useful when dealing with file operations and management. The following function (void EnumDirFiles(...)), can be used as is to simply list all the files within a directory and all the files within the subdirectories of the directory. The usages for such a function are vast, as this is a basis for all file enumeration operations.

I hope you will find this as useful as I do!

Implementation

int main()
{
	EnumDirFiles("C:\\Program Files"); // List all files within the Program Files directory.

return 0;
}

Recursive Function Definition

void EnumDirFiles(char *lpszDir)
{
	HANDLE hDir;
	BOOL bDone = FALSE;
	WIN32_FIND_DATA FileData;
	char szFind[512];

strcpy(szFind, lpszDir);
strcat(szFind, "\\*");
hDir = FindFirstFile(szFind, &FileData);
if(hDir == INVALID_HANDLE_VALUE)
{
printf("Invalid Directory: \"%s\"\n", lpszDir);
return;
}

while(!bDone)
{
if(FileData.cFileName[0] != '.') // Exclude "." and ".."
{
char szFullFile[512];
strcpy(szFullFile, lpszDir);
strcat(szFullFile, "\\");
strcat(szFullFile, FileData.cFileName);

if(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
printf("- Listing Directory: %s\n", szFullFile);
EnumDirFiles(szFullFile);
}
else
printf("%s\n", szFullFile);
}

if(!FindNextFile(hDir, &FileData))
{
if(GetLastError() == ERROR_NO_MORE_FILES)
{
bDone = TRUE;
}
else
{
printf("Unable to enumerate the next file.\n");
bDone = TRUE;
}
}
}

// Close the search handle.
FindClose(hDir);
}

About November 2006

This page contains all entries posted to Photon Development in November 2006. They are listed from oldest to newest.

December 2006 is the next archive.

Many more can be found on the main index page or by looking through the archives.