the MAIL command in UNIX and Pipes [Archive] - C Board

PDA

View Full Version : the MAIL command in UNIX and Pipes


RoshanX
10-12-2003, 09:11 PM
hi all,
I am wirting a program which will sent a certain recipent a email ( the email address is taken from the command line). The email contains the current processes that are running in the machine. The subject line will have something like "there are X no of users running X number of processes". It should do this with pipes. (popen()). The program is working. But I am having trouble with the SUBJECT line. The reciving mail won't have a subject. ( the subject will be NONE.) The source code is as follows. The section where the mail is sent is in red.

#include<stdio.h>
#include<stdlib.h>
#define BUFFLEN 40 /* length of the array that will hold all the processes */
#define SIZE 100 /* the initial size of the array to hold all the processes */
#define COMMAND "ps -e -o uid -o pid -o fname" /* get all the process names */
char** list; /*the column vector of the 2D array to hold filenames */
void die(char*); /* die with msg */

int main()
{
FILE* pipe_id;
int i=0,j; /* conter variables */
char buff[BUFFLEN];
int user_count;
int proc_count;
char subject[80]; /* the subject line */
char recpt[50]; /* the recipient of the email*/
char mail_command[80];
printf("The mail recipient : ");
fscanf(stdin,"%s",recpt);

/* allocate the column vector of the 2D character array */
if((list=(char**)malloc(sizeof(char*)*SIZE))==NULL )
die("Memory allocation error.\n");

/* open pipe connection */
if ((pipe_id=popen(COMMAND,"r"))==NULL)
die("Pipe open failiure. Abort");

/*read each line from the pipe and write it to the array */
while(fgets(buff, BUFFLEN, pipe_id)!= NULL)
{
if ((i+1)>SIZE) /* reallocation required */
list=(char**)realloc((char**)list,sizeof(char*)*(i +100)); /* reallocate the column vector with 100 more elements */

if ((list[i]=(char*)malloc(sizeof(char)*BUFFLEN))==NULL) /* allocate rows of the 2D char array */
die("Memory allocation erro. \n");

strcpy(list[i],buff); /* copy the line read from the pipe to the array element */
i++;
}
// get_counts(list,&user_count,&proc_count);
pclose(pipe_id);

sprintf(subject,"\"There are %d no of users using %d processers\"",10,100);
sprintf(mail_command,"mail -s %s %s ",subject,recpt);
printf("%s\n",mail_command);
pipe_id=popen(mail_command,"w");
for(j=0;j<i;j++)
{
fprintf(pipe_id,"%s",list[j]);
}
fprintf(pipe_id,"%c",EOF);

pclose(pipe_id);
}


how to solve this ?

twm
10-13-2003, 08:53 AM
mail doesn't allow you to include a subject, you should avoid it wherever possible in favor of mailx (or Mail).

RoshanX
10-13-2003, 11:28 AM
Thanks for the relply. Yer..I solved the problem by replacing "mail" with "Mail". It works now.

But , "mail" would allow you to specify the subject if you are doing this diectly in the command line.

twm
10-14-2003, 07:43 AM
>But , "mail" would allow you to specify the subject if you are doing this diectly in the command line.
Allow me to speculate wildly then. :) On the command line 'mail' is a link to Mail or mailx, but for some reason, in your program 'mail' calls the real mail. Of course, I'm not familiar enough with C to speculate on the 'for some reason' part. ;)

Hammer
10-14-2003, 08:05 AM
>>sprintf(mail_command,"mail -s %s %s ",subject,recpt);
A classic example of a security hazzard. As twm implied, who knows what "mail" actually is. You should be using the full path to the executable: /usr/bin/mail (or whatever)

rotis23
10-14-2003, 03:12 PM
It would be just as easy to write a small mail client that talks SMTP to a mail server using sockets.

Check out sockets and the SMTP RFC.

twm
10-15-2003, 06:44 AM
>It would be just as easy to write a small mail client that talks SMTP to a mail server using sockets.
So you're suggesting he write a mail client instead of simply piping to an existing mail client, thus tripling(probably way more) his work load and potential bug count? That sounds like something Windows would do, but we Unix users are above that kind of thing. :D

rotis23
10-15-2003, 08:57 AM
Its just as many lines of code just to connect to an SMTP server and send:

helo
mail from: blah@blah.com
rcpt to: blah2@blah.com
data
subject: my subject
blah blah blah
.
quit

close connection.

The alternative is to open a pipe, probably invoke a shell, call another program, and spark another process.

please don't talk to me about windows.

twm
10-15-2003, 09:22 AM
>Its just as many lines of code just to connect to an SMTP server and send:
Really?

It would be just as easy to write a small mail client that talks SMTP to a mail server using sockets.

The way I read this statement is that you would actually write the socket code to connect to a mail server. Setting up a socket, opening and closing the connection and any error checking code alone is longer than opening a pipe and using it. Then of course you need to actually use the socket, this adds even more code. But then you have to consider writing the code to speak SMTP and glue all of this to your program. But let's not talk so much about length of code as complexity and maintenance. By writing something that already exists, you increase the complexity of your program, which is that much more for someone maintaining it to understand. On top of understanding the code, what if it needs to be changed in any signifigant way? Using pipes you could likely just change the program used in a single instance. Using your method, a large portion of the code would have to be cut out, replaced, debugged and tested.

>The alternative is to open a pipe, probably invoke a shell, call another program, and spark another process.
All of which are inexpensive enough to make that solution a pretty big win. If it turns out to be too slow after stress testing in a working environment, you can say you tried and then do something else more along your lines. But I would wager the chances of that being needed are slim.

Once again I ask: Why bother writing a mail client when there are already several that come with Unix/Linux by default and are highly scriptable?

rotis23
10-15-2003, 10:01 AM
Write it in bash.

rotis23
10-15-2003, 10:06 AM
ps -e -o uid -o pid -o fname | mail me@domain.com -s "ps command output"

twm
10-15-2003, 10:06 AM
So we're not using C anymore? Well, then your way is probably as long as the equivalent C program using pipes, just as you said.

RoshanX
10-15-2003, 11:29 AM
What I really want to know is this, Forget about all the security risks and other stuff.........

$ mail -s " some kind of subject " recipient@foo.com

This will send a mail to the recipient with the SUBJECT line.

But if I do the samething with C ( using pipes or just execl() or system()) , it will send the mail, but without the SUBJECT line. WHY IS THAT ?

rotis23
10-16-2003, 06:19 AM
Does it work the same on the command line?

Try putting username before the subject if you're using linux.

twm
10-16-2003, 07:53 AM
Just a quick note rotis in case you didn't know this:

ps -e -o uid -o pid -o fname | mail me@domain.com -s "ps command output"

The -o option allows a comma separated list. So you should be able to speed yourself up a hair by doing this:

ps -eo uid,pid,fname | mail me@domain.com -s "ps command output"

Scary, huh? :D

>WHY IS THAT ?
I have no clue. Like I said, I'm not familiar enough with C to speculate. Try adding the -v switch to get some extra info on delivery, that may be enlightening. :)

rotis23
10-16-2003, 09:04 AM
twm, I think you're getting confused about who posted.

twm
10-16-2003, 10:50 AM
>twm, I think you're getting confused about who posted.
How so? The first part was to you, the second to RoshanX. As far as I can tell, each comment was sent to the proper person.

RoshanX
10-16-2003, 12:25 PM
Nope , won't work. It will work if I use "Mail" instead of "mail". And I am using a sun os.

rotis23
10-16-2003, 12:45 PM
try doing something like:

...
pipe_id=popen(mail_command,"w");
fprintf(pipe_id,"Subject: %s\n",subject); //subject placed here
for(j=0;j<i;j++)
{
fprintf(pipe_id,"%s",list[j]);
}
fprintf(pipe_id,"%c",EOF);
...

I'm not sure if you need the newline or if it's best to use it there, but it should work.

Longie
10-21-2003, 10:40 PM
This is a tad late, but you could always do something like this (to solve the discrepency about "mail" and "Mail" :P)



#define YourEmail "me@mydomain.com"
FILE *email;
char cmd[64] = "";

if((email = fopen("mail", "a+")) == NULL)
die("Cannot open text file for email.\n");

fprintf(email, "To: %s\n", recpt);
fprintf(email, "From: %s\n", YourEmail);
fprintf(email, "Subject: There are %d users using %d processes\n\n", user_count, proc_count);

/*
** fprintf(email, "message line here\n");
** etc
*/

fclose(email);

sprintf(cmd, "/usr/lib/sendmail %s < mail", recpt);
system(cmd);



Not the best way, but it works, and I know, I had to use system() :(

I'm sure there are other ways, such as "fastmail", or "sendmail -t with popen() and pclose()", but like I said, this was just an idea I had and decided to post because of the "mail" "Mail" discussion and to show that the code for it isn't that long in C, as the other person suggested.