/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2013-2021 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see . */
#include "mh.h"
#include "mailutils/kwd.h"
#include "mailutils/folder.h"
#include "mailutils/auth.h"
#include "mailutils/datetime.h"
#include
static char prog_doc[] = N_("Check for messages");
static char args_doc[] = N_("USER [USER...]");
int date_option = 1;
int apop_option;
char *remote_host;
char *remote_user;
#define NOTIFY_MAIL 0x1
#define NOTIFY_NOMAIL 0x2
#define NOTIFY_ALL (NOTIFY_MAIL|NOTIFY_NOMAIL)
int notify = NOTIFY_ALL;
static struct mu_kwd notifytab[] = {
{ "mail", NOTIFY_MAIL },
{ "nomail", NOTIFY_NOMAIL },
{ "all", NOTIFY_ALL },
{ NULL }
};
static void
set_notify (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
{
int n;
if (mu_kwd_xlat_name (notifytab, arg, &n))
{
mu_parseopt_error (po, "unknown notify argument: %s", arg);
exit (po->po_exit_error);
}
notify |= n;
}
static void
clr_notify (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
{
int n;
if (mu_kwd_xlat_name (notifytab, arg, &n))
{
mu_parseopt_error (po, "unknown notify argument: %s", arg);
exit (po->po_exit_error);
}
notify &= ~n;
}
static struct mu_option options[] = {
{ "date", 0, NULL, MU_OPTION_DEFAULT,
N_("print out the last date mail was read"),
mu_c_bool, &date_option },
{ "notify", 0, "all|mail|nomail", MU_OPTION_DEFAULT,
N_("produce a message upon these events"),
mu_c_string, NULL, set_notify },
{ "nonotify", 0, "all|mail|nomail", MU_OPTION_DEFAULT,
N_("disable notification"),
mu_c_string, NULL, clr_notify },
{ "host", 0, N_("URL"), MU_OPTION_DEFAULT,
N_("check mail on this host or URL"),
mu_c_string, &remote_host },
{ "user", 0, N_("NAME"), MU_OPTION_DEFAULT,
N_("set user name for remote mailbox access"),
mu_c_string, &remote_user },
{ "apop", 0, NULL, MU_OPTION_DEFAULT,
N_("enable APOP"),
mu_c_bool, &apop_option },
MU_OPTION_END
};
static char *
attach_auth_ticket (mu_mailbox_t mbox)
{
char *filename = NULL;
mu_folder_t folder = NULL;
mu_authority_t auth = NULL;
if (mu_mailbox_get_folder (mbox, &folder) == 0
&& mu_folder_get_authority (folder, &auth) == 0
&& auth)
{
mu_wicket_t wicket;
int rc;
filename = mu_tilde_expansion (mu_ticket_file, MU_HIERARCHY_DELIMITER,
NULL);
mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
("Reading user ticket file %s", filename));
if ((rc = mu_file_wicket_create (&wicket, filename)) == 0)
{
mu_ticket_t ticket;
if ((rc = mu_wicket_get_ticket (wicket, NULL, &ticket)) == 0)
{
rc = mu_authority_set_ticket (auth, ticket);
mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
("Retrieved and set ticket: %d", rc));
}
else
mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
("Error retrieving ticket: %s\n",
mu_strerror (rc)));
mu_wicket_destroy (&wicket);
}
else
mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
("Error creating wicket: %s\n", mu_strerror (rc)));
if (rc)
{
free (filename);
filename = NULL;
}
}
return filename;
}
int
checkmail (const char *username, int personal)
{
int rc;
mu_url_t url;
mu_mailbox_t mbox;
size_t recent = 0, count = 0;
int status = 1;
int have_user;
if (remote_host)
{
static mu_url_t pop_hint;
if (!pop_hint)
{
rc = mu_url_create (&pop_hint, "pop://");
if (rc)
{
mu_error ("cannot create URL hint: %s", mu_strerror (rc));
exit (2);
}
}
rc = mu_url_create_hint (&url, remote_host, MU_URL_PARSE_DEFAULT,
pop_hint);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_url_create_hint", remote_host,
rc);
exit (2);
}
if (apop_option)
{
rc = mu_url_set_auth (url, "+APOP");
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_url_set_auth", "+APOP", rc);
exit (2);
}
}
}
else
{
char *s;
rc = mu_construct_user_mailbox_url (&s, username);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_construct_user_mailbox_url",
username, rc);
exit (2);
}
rc = mu_url_create (&url, s);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_url_create", s, rc);
exit (2);
}
free (s);
}
rc = mu_mailbox_create_from_url (&mbox, url);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_create_from_url",
mu_url_to_string (url), rc);
exit (2);
}
if (personal)
{
char *filename = attach_auth_ticket (mbox);
have_user = mu_url_has_flag (url, MU_URL_USER);
if (!have_user)
{
mu_url_t tickurl;
if (mu_wicket_file_match_url (filename, url, MU_URL_PARSE_ALL,
&tickurl) == 0)
{
have_user = mu_url_has_flag (tickurl, MU_URL_USER);
mu_url_destroy (&tickurl);
}
}
free (filename);
}
else
have_user = 0;
if (!have_user)
{
mu_url_t turl;
mu_mailbox_get_url (mbox, &turl);
rc = mu_url_set_user (turl, username);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_url_set_user", username, rc);
exit (2);
}
}
rc = mu_mailbox_open (mbox, MU_STREAM_READ);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_open",
mu_url_to_string (url), rc);
exit (2);
}
rc = mu_mailbox_messages_count (mbox, &count);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_messages_count",
mu_url_to_string (url), rc);
if (count)
{
status = 0;
if (notify & NOTIFY_MAIL)
{
mu_off_t mbsiz = 0;
int newmail = 0;
rc = mu_mailbox_message_unseen (mbox, &recent);
switch (rc)
{
case 0:
newmail = 1;
break;
case MU_ERR_NOENT:
newmail = 0;
break;
default:
if (rc != ENOSYS && rc != MU_ERR_INFO_UNAVAILABLE)
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_messages_unseen",
mu_url_to_string (url), rc);
rc = mu_mailbox_messages_recent (mbox, &recent);
if (rc == 0)
newmail = recent > 0;
}
if (rc)
{
if (rc != ENOSYS && rc != MU_ERR_INFO_UNAVAILABLE)
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_messages_recent",
mu_url_to_string (url), rc);
mu_mailbox_get_size (mbox, &mbsiz);
if (personal)
mu_printf (ngettext ("You have %lu message",
"You have %lu messages",
count),
(unsigned long) count);
else
mu_printf (ngettext ("%s has %lu message",
"%s has %lu messages",
count),
username, (unsigned long) count);
mu_printf (ngettext (" (%lu byte)",
" (%lu bytes)",
mbsiz), (unsigned long) mbsiz);
}
else
{
if (personal)
mu_printf (newmail ? _("You have new mail waiting") :
_("You have old mail waiting"));
else
mu_printf (newmail ? _("%s has new mail waiting") :
_("%s has old mail waiting"), username);
}
if (date_option)
{
time_t t;
if (mu_mailbox_access_time (mbox, &t) == 0)
mu_c_streamftime (mu_strout,
_("; last read on %a, %d %b %Y %H:%M:%S %z"),
localtime (&t), NULL);
}
mu_printf ("\n");
}
}
else
{
status = 1;
if (notify & NOTIFY_NOMAIL)
{
if (personal)
mu_printf (_("You don't have any mail waiting\n"));
else
mu_printf (_("%s doesn't have any mail waiting\n"),
username);
}
}
mu_mailbox_destroy (&mbox);
return status;
}
int
main (int argc, char **argv)
{
int rc = 0;
mh_getopt (&argc, &argv, options, 0, args_doc, prog_doc, NULL);
if (argc == 0)
{
if (remote_user)
rc |= checkmail (remote_user, 1);
else
{
struct passwd *pw = getpwuid (getuid ());
if (!pw)
{
mu_error (_("cannot determine my username"));
return 2;
}
rc |= checkmail (pw->pw_name, 1);
}
}
else if (remote_user)
{
mu_error (_("no arguments are allowed when the -user option is given"));
return 2;
}
else
while (argc--)
rc |= checkmail (*argv++, 0);
return rc;
}