Back to index

courier  0.68.2
Classes | Defines | Functions | Variables
pcpd.c File Reference
#include "config.h"
#include "pcp.h"
#include "pcpdtimer.h"
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include "liblock/config.h"
#include "liblock/liblock.h"
#include "numlib/numlib.h"
#include "maildir/maildircache.h"
#include "pcpdauth.h"
#include "pcpdauthtoken.h"
#include "calendardir.h"

Go to the source code of this file.

Classes

struct  proxy_list
struct  readnewevent_s
struct  book_time_list
struct  report_conflict_info
struct  extra_conflict_info
struct  list_struct
struct  list_item
struct  retrinfo
struct  retrinfo_event_list
struct  uncancel_list
struct  acl_list
struct  get_acl
struct  userid_info
struct  relogin_struct

Defines

#define exit(_a_)   _exit(_a_)
#define PROXY_NEW   1
#define PROXY_IGNORE   2

Functions

static void inactive (struct PCP *p, void *dummy)
static int inputchar (struct PCP *pcp)
struct PCPopen_calendar (const char *p)
static void error (int n)
static void proxy_list_rset ()
static int addrcmp (const char *a, const char *b)
static struct proxy_listproxy (const char *proxy_userid, char **errmsg)
static void rset (struct PCP *pcp)
static int readnewevent_callback (char *p, int n, void *vp)
static void proxy_error (const char *n, const char *msg)
static int mkparticipants (struct PCP_save_event *se)
static struct PCP_new_eventidreadnewevent (struct PCP *pcp)
static int do_report_conflict (const char *e, time_t start, time_t end, const char *addr, void *vp)
static void report_conflict_destroy (struct report_conflict_info *p)
static void rebook (struct PCP *, void *)
static void rebook_installtimeout (struct PCP *pcp)
static void dobook (struct PCP *pcp)
static int list_callback (struct PCP_list_all *p, void *vp)
static int list (struct PCP *pcp)
static int callback_retr_date (struct PCP_retr *r, time_t from, time_t to, void *vp)
static int callback_retr_participants (struct PCP_retr *r, const char *n, const char *id, void *vp)
static int callback_retr_status (struct PCP_retr *r, int status, void *vp)
static int callback_retr_begin (struct PCP_retr *r, void *vp)
static int callback_retr_headers (struct PCP_retr *r, const char *h, const char *v, void *vp)
static int callback_retr_message (struct PCP_retr *r, const char *ptr, int l, void *vp)
static int callback_retr_end (struct PCP_retr *r, void *vp)
static int retr (struct PCP *pcp)
static int uncancel_callback (const char *event, time_t from, time_t to, const char *addr, void *vp)
static int list_acl_callback (const char *who, int flags, void *dummy)
static void listacls (struct PCP *pcp)
static int open_event_participant (struct PCP_retr *r, const char *n, const char *id, void *vp)
static int check_acl (int, int)
static int doline (struct PCP *pcp, char *p, int acl_flags)
static RETSIGTYPE catch_sig (int sig_num)
static void setsigs ()
static int get_acl_callback (const char *w, int f, void *dummy)
static void mainloop (struct PCP *pcp)
static void accept_pcpd (int, int, int, int)
static void start ()
static int callback_userid (struct userid_callback *a, void *vp)
static int callback_login (struct userid_callback *a, void *vp)
static char * login (int, int *)
static int accept_sock (int sock)
static int callback_cache_search (uid_t u, gid_t g, const char *dir, void *vp)
int main (int argc, char **argv)

Variables

static char * userid
static char * proxy_userid
static char * deleted_eventid
static struct PCP_new_eventidnew_eventid
static int conflict_flag
static int force_flag
static int notbooked
static struct PCP_commit
static struct PCP_event_timenew_commit_times
static struct
PCP_event_participant
new_commit_participants
static char * new_commit_participants_buf
static struct pcpdtimer
static int termsig
static int need_rset
static char * input_buffer = NULL
static size_t input_buffer_len = 0
static size_t input_line_len
static time_t prev_time
static char * inp_ptr
static int inp_left
struct proxy_listproxy_list = NULL

Class Documentation

struct proxy_list

Definition at line 246 of file pcpd.c.

Collaboration diagram for proxy_list:
Class Members
int flags
struct PCP_new_eventid * newevent
struct proxy_list * next
char * old_event_id
struct PCP * proxy
char * userid
struct readnewevent_s

Definition at line 389 of file pcpd.c.

Collaboration diagram for readnewevent_s:
Class Members
int cnt
time_t last_noop_time
struct PCP * pcp
int seendot
int seeneof
int seeneol
int sentprompt
FILE * tmpfile
struct book_time_list

Definition at line 732 of file pcpd.c.

Collaboration diagram for book_time_list:
Class Members
struct book_time_list * next
struct report_conflict_info

Definition at line 737 of file pcpd.c.

Collaboration diagram for report_conflict_info:
Class Members
char * conflict_addr
time_t conflict_end
char * conflict_eventid
time_t conflict_start
struct report_conflict_info * next
struct extra_conflict_info

Definition at line 745 of file pcpd.c.

Collaboration diagram for extra_conflict_info:
Class Members
struct report_conflict_info ** conflict_list
const char * proxy_addr
struct list_struct

Definition at line 986 of file pcpd.c.

Collaboration diagram for list_struct:
Class Members
struct list_item * event_list
struct list_item ** last_event
struct list_item

Definition at line 991 of file pcpd.c.

Collaboration diagram for list_item:
Class Members
time_t end
char * event_id
struct list_item * next
time_t start
struct retrinfo

Definition at line 1106 of file pcpd.c.

Collaboration diagram for retrinfo:
Class Members
struct retrinfo_event_list * event_list
const char ** event_list_array
int status
int text_flag
int text_seen_eol
struct retrinfo_event_list

Definition at line 1114 of file pcpd.c.

Collaboration diagram for retrinfo_event_list:
Class Members
char * event_id
struct retrinfo_event_list * next
struct uncancel_list

Definition at line 1368 of file pcpd.c.

Collaboration diagram for uncancel_list:
Class Members
char * addr
time_t from
char * id
struct uncancel_list * next
time_t to
struct acl_list

Definition at line 1406 of file pcpd.c.

Collaboration diagram for acl_list:
Class Members
char * addr
int flags
char * name
struct acl_list * next
char * who
struct get_acl

Definition at line 1955 of file pcpd.c.

Class Members
int flags
const char * who
struct userid_info

Definition at line 2117 of file pcpd.c.

Class Members
int isproxy
char * userid
struct relogin_struct

Definition at line 2308 of file pcpd.c.

Class Members
int needauthtoken
const char * userid
time_t when

Define Documentation

#define exit (   _a_)    _exit(_a_)

Definition at line 37 of file pcpd.c.

#define PROXY_IGNORE   2

Definition at line 255 of file pcpd.c.

#define PROXY_NEW   1

Definition at line 254 of file pcpd.c.


Function Documentation

static void accept_pcpd ( int  sock,
int  pubsock,
int  privsock,
int  flag 
) [static]

Definition at line 2241 of file pcpd.c.

{
       int fd;
       pid_t pid;
       struct PCP *pcp;

       if ((fd=accept_sock(sock)) < 0)
              return;

       if (fcntl(fd, F_SETFL, 0) < 0)
       {
              fprintf(stderr, "CRIT: fcntl() failed: %s\n", strerror(errno));
              close(fd);
              return;
       }

       maildir_cache_purge();
       pid=fork();

       if (pid < 0)
       {
              fprintf(stderr, "CRIT: fork() failed: %s\n", strerror(errno));
              close(fd);
              return;
       }

       if (pid)
       {
              close(fd);
              return;       /* Parent resumes listening */
       }

       /* child */
       signal(SIGCHLD, SIG_DFL);

       close(pubsock);
       close(privsock);

       close(0);
       if (dup(fd) != 0)
              exit(0);
       close(1);
       if (dup(fd) != 1)
              exit(0);
       close(fd);
       userid=login(flag, &flag);

       pcp=pcp_open_dir(".", userid);

       if (pcp && flag && pcp_cleanup(pcp))
       {
              pcp_close(pcp);
              fprintf(stderr, "CRIT: pcp_cleanup failed\n");
              pcp=NULL;
       }

       if (!pcp)
       {
              fprintf(stderr, "CRIT: pcp_open_dir failed\n");
              perror("pcp_open_dir");
              exit(1);
       }

       mainloop(pcp);
       exit(0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int accept_sock ( int  sock) [static]

Definition at line 2231 of file pcpd.c.

{
       struct sockaddr_un saddr;
       socklen_t saddr_len;

       saddr_len=sizeof(saddr);

       return (accept(sock, (struct sockaddr *)&saddr, &saddr_len));
}

Here is the caller graph for this function:

static int addrcmp ( const char *  a,
const char *  b 
) [static]

Definition at line 281 of file pcpd.c.

{
       char *aa=NULL;
       const char *h=auth_myhostname();
       int rc;

       if (!h)
              return (1);

       if (strchr(a, '@') == NULL)
       {
              aa=malloc(strlen(a)+strlen(h)+2);

              if (!aa)
              {
                     fprintf(stderr, "NOTICE: malloc: out of memory.\n");
                     return (1);
              }
              strcat(strcat(strcpy(aa, a), "@"), h);
              rc=addrcmp(aa, b);
              free(aa);
              return (rc);
       }

       if (strchr(b, '@') == NULL)
       {
              aa=malloc(strlen(b)+strlen(h)+2);

              if (!aa)
              {
                     fprintf(stderr, "NOTICE: malloc: out of memory.\n");
                     return (1);
              }
              strcat(strcat(strcpy(aa, b), "@"), h);
              rc=addrcmp(a, aa);
              free(aa);
              return (rc);
       }

       rc=strcasecmp(a, b);
       return (rc);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int callback_cache_search ( uid_t  u,
gid_t  g,
const char *  dir,
void *  vp 
) [static]

Definition at line 2314 of file pcpd.c.

{
       struct relogin_struct *rs=(struct relogin_struct *)vp;
       time_t login_time, now;
       int reset_flag;
       char *token=NULL;

       login_time=rs->when;
       time(&now);

       reset_flag= login_time <= now - TIMEOUT;

       if (reset_flag)
       {
              if (rs->needauthtoken)
              {
                     token=authtoken_create(rs->userid, now);
                     if (!token)
                     {
                            fprintf(stderr,
                                   "ALERT: authtoken_create() failed.\n");
                            return (1);
                     }
              }
              maildir_cache_start();
       }

       libmail_changeuidgid(u, g);

       if (chdir(dir) < 0)
       {
              maildir_cache_cancel();
              fprintf(stderr, "NOTICE: chdir(%s) failed: %s\n", dir, strerror(errno));
              return (-1);
       }

       alarm(0);
       if (reset_flag)
       {
              maildir_cache_save(rs->userid, now, dir, u, g);
              if (rs->needauthtoken)
              {
                     printf("102 %s logged in.\n", token);
                     free(token);
              }
       }
       else if (rs->needauthtoken) /* Not a proxy connection */
              printf("200 Ok\n");
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int callback_login ( struct userid_callback a,
void *  vp 
) [static]

Definition at line 2148 of file pcpd.c.

{
       struct userid_info *uinfo=(struct userid_info *)vp;
       struct stat stat_buf;
       time_t t;
       char curdir[1024];
       char *token=NULL;

       if (stat(a->homedir, &stat_buf) < 0)
              return (-1);

       if (stat_buf.st_mode & S_ISVTX)
       {
              errno=EAGAIN;
              return (1);
       }

       time(&t);
       if (!uinfo->isproxy)
       {
              token=authtoken_create(uinfo->userid, t);
              if (!token)
              {
                     fprintf(stderr, "NOTICE: authtoken_create() failed.\n");
                     maildir_cache_cancel();
                     return (1);
              }
       }

       maildir_cache_start();

       libmail_changeuidgid(a->uid, getgid());

       if (chdir(a->homedir) < 0)
       {
              free(token);
              fprintf(stderr, "NOTICE: chdir(%s) failed: %s\n", a->homedir,
                     strerror(errno));
              maildir_cache_cancel();
              exit(1);
       }

       if (chdir(a->maildir && *a->maildir ? a->maildir:"Maildir") < 0)
       {
              free(token);
              fprintf(stderr, "NOTICE: chdir(Maildir) failed: %s\n",
                     strerror(errno));
              maildir_cache_cancel();
              exit(1);
       }

       mkdir("calendar", 0700);
       if (chdir("calendar") < 0)
       {
              free(token);
              fprintf(stderr, "NOTICE: chdir(calendar) failed: %s\n",
                     strerror(errno));
              maildir_cache_cancel();
              exit(1);
       }

       curdir[sizeof(curdir)-1]=0;
       if (getcwd(curdir, sizeof(curdir)-1) == 0)
       {
              fprintf(stderr, "NOTICE: getcwd() failed: %s\n",
                     strerror(errno));
              maildir_cache_cancel();
              exit(1);
       }

       maildir_cache_save(uinfo->userid, t, curdir, a->uid, getgid());

       alarm(0);
       if (!uinfo->isproxy)
       {
              printf("102 %s logged in.\n", token);
              free(token);
       }
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int callback_retr_begin ( struct PCP_retr r,
void *  vp 
) [static]

Definition at line 1170 of file pcpd.c.

{
       struct retrinfo *ri=(struct retrinfo *)vp;

       ri->text_flag=0;
       ri->text_seen_eol=1;

       return (0);
}

Here is the caller graph for this function:

static int callback_retr_date ( struct PCP_retr r,
time_t  from,
time_t  to,
void *  vp 
) [static]

Definition at line 1119 of file pcpd.c.

{
       char from_buf[15], to_buf[15];

       pcp_gmtimestr(from, from_buf);
       pcp_gmtimestr(to, to_buf);

       printf("105 %s %s %s event found\n",
              r->event_id, from_buf, to_buf);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int callback_retr_end ( struct PCP_retr r,
void *  vp 
) [static]

Definition at line 1243 of file pcpd.c.

{
       struct retrinfo *ri=(struct retrinfo *)vp;

       if (ri->text_flag)
       {
              if (!ri->text_seen_eol)
                     putchar('\n');
              printf(".\n");
       }
       return (0);
}

Here is the caller graph for this function:

static int callback_retr_headers ( struct PCP_retr r,
const char *  h,
const char *  v,
void *  vp 
) [static]

Definition at line 1180 of file pcpd.c.

{
       struct retrinfo *ri=(struct retrinfo *)vp;
       int lastchar;

       if (!ri->text_flag)
       {
              ri->text_flag=1;
              printf("107 %s follows\n", r->event_id);
       }

       if (*h == '.')
              putchar('.');
       printf("%s: ", h);

       while (*v && isspace((int)(unsigned char)*v))
              ++v;

       lastchar=' ';

       while (*v)
       {
              if ((int)(unsigned char)*v >= ' ' ||
                  *v == '\n' || *v == '\t')
              {
                     putchar(*v);
                     lastchar=*v;
              }
              ++v;
       }
       if (lastchar != '\n')
              putchar('\n');
       return (0);
}

Here is the caller graph for this function:

static int callback_retr_message ( struct PCP_retr r,
const char *  ptr,
int  l,
void *  vp 
) [static]

Definition at line 1218 of file pcpd.c.

{
       struct retrinfo *ri=(struct retrinfo *)vp;

       if (!ri->text_flag)
       {
              ri->text_flag=1;
              printf("107 %s follows\n", r->event_id);
       }

       while (l)
       {
              if (ri->text_seen_eol && *ptr == '.')
                     putchar('.');
              ri->text_seen_eol= *ptr == '\n';
              putchar(*ptr);
              ++ptr;
              --l;
       }
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int callback_retr_participants ( struct PCP_retr r,
const char *  n,
const char *  id,
void *  vp 
) [static]

Definition at line 1132 of file pcpd.c.

{
       printf("106 %s %s is a participant\n", r->event_id, n);
       return (0);
}

Here is the caller graph for this function:

static int callback_retr_status ( struct PCP_retr r,
int  status,
void *  vp 
) [static]

Definition at line 1140 of file pcpd.c.

{
       char status_buf[256];
       const char *comma="";

       status_buf[0]=0;

       if (status & LIST_CANCELLED)
       {
              strcat(strcat(status_buf, comma), "CANCELLED");
              comma=",";
       }

       if (status & LIST_BOOKED)
       {
              strcat(strcat(status_buf, comma), "BOOKED");
              comma=",";
       }

       if (status & LIST_PROXY)
       {
              strcat(strcat(status_buf, comma), "PROXY");
              comma=",";
       }
       if (status_buf[0])
              printf("110 %s %s\n", r->event_id, status_buf);
       return (0);
}

Here is the caller graph for this function:

static int callback_userid ( struct userid_callback a,
void *  vp 
) [static]

Definition at line 2122 of file pcpd.c.

{
       struct userid_info *uinfo=(struct userid_info *)vp;
       char *u=strdup(a->userid);
       struct stat stat_buf;

       if (!u)
              return (-1);

       if (stat(a->homedir, &stat_buf) < 0)
       {
              free(u);
              return (-1);
       }

       if (stat_buf.st_mode & S_ISVTX)
       {
              free(u);
              errno=EAGAIN;
              return (1);
       }

       uinfo->userid=u;
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static RETSIGTYPE catch_sig ( int  sig_num) [static]

Definition at line 1932 of file pcpd.c.

{
       termsig=1;
       signal(SIGALRM, catch_sig);
       alarm(2);

#if RETSIGTYPE != void
       return (0);
#endif
}

Here is the caller graph for this function:

static int check_acl ( int  flags,
int  bit 
) [static]

Definition at line 1923 of file pcpd.c.

{
       if (flags & bit)
              return (0);

       printf("500 Permission denied.\n");
       return (1);
}

Here is the caller graph for this function:

static int do_report_conflict ( const char *  e,
time_t  start,
time_t  end,
const char *  addr,
void *  vp 
) [static]

Definition at line 750 of file pcpd.c.

{
       struct extra_conflict_info *eci=(struct extra_conflict_info *)vp;
       struct report_conflict_info **p=eci->conflict_list;
       struct report_conflict_info *q=malloc(sizeof(**p));

       if (!q)
              return (-1);

       if (eci->proxy_addr)
              addr=eci->proxy_addr;

       if ((q->conflict_eventid=strdup(e)) == NULL)
       {
              free(q);
              return (-1);
       }

       if ((q->conflict_addr=strdup(addr)) == NULL)
       {
              free(q->conflict_eventid);
              free(q);
              return (-1);
       }

       while (*p)
       {
              p= &(*p)->next;
       }

       *p=q;
       q->next=0;
       q->conflict_start=start;
       q->conflict_end=end;
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dobook ( struct PCP pcp) [static]

Definition at line 820 of file pcpd.c.

{
       struct book_time_list *list, **last;
       unsigned n=0;
       const char *p;
       int rc=0;
       struct PCP_event_time *new_times=NULL;
       struct report_conflict_info *conflict_list;

       list=NULL;
       last= &list;

       while ((p=strtok(NULL, " ")) != NULL)
       {
              char from_s[14+1];
              char to_s[14+1];

              if (strlen(p) != 14 + 14 + 1 || p[14] != '-')
              {
                     printf("500 Syntax error.\n");
                     rc= -1;
                     break;
              }

              memcpy(from_s, p, 14);
              memcpy(to_s, p+15, 14);
              from_s[14]=0;
              to_s[14]=0;

              if ( (*last=malloc(sizeof(**last))) == NULL)
              {
                     printf("500 %s\n", strerror(errno));
                     rc= -1;
                     break;
              }

              (*last)->next=NULL;
              if (((*last)->times.start=pcp_gmtime_s(from_s)) == 0 ||
                  ((*last)->times.end=pcp_gmtime_s(to_s)) == 0)
              {
                     printf("500 Invalid date/time\n");
                     rc= -1;
                     break;
              }

              last=&(*last)->next;
              ++n;
       }

       if (rc == 0 && n == 0)
       {
              printf("500 Syntax error\n");
              rc= -1;
       }

       if (rc == 0 && (new_times=calloc(n, sizeof(struct PCP_event_time)))
           == NULL)
       {
              printf("500 %s\n", strerror(errno));
              rc= -1;
       }

       if (rc == 0)
       {
              struct book_time_list *l;
              const struct PCP_event_time *save_times;
              unsigned n_save_times;
              struct proxy_list *pr;
              int is_conflict;
              struct extra_conflict_info eci;

              n=0;
              for (l=list; l; l=l->next)
                     new_times[n++]= l->times;

              save_times=new_commit.event_times;
              n_save_times=new_commit.n_event_times;

              new_commit.event_times=new_times;
              new_commit.n_event_times=n;

              eci.conflict_list= &conflict_list;

              conflict_list=NULL;
              new_commit.add_conflict_callback=do_report_conflict;
              new_commit.add_conflict_callback_ptr= &eci;
              new_commit.flags=
                     (conflict_flag ? PCP_OK_CONFLICT:0) |
                     (force_flag ? PCP_OK_PROXY_ERRORS:0);

              notbooked=1;
              is_conflict=0;

              for (pr=proxy_list; pr; pr=pr->next)
              {
                     eci.proxy_addr=pr->userid;

                     if (pr->flags & PROXY_NEW)
                            if (pcp_book(pr->proxy,
                                        pr->newevent, &new_commit))
                                   is_conflict=1;
              }

              if (proxy_userid)
                     new_commit.flags |= PCP_BYPROXY;

              eci.proxy_addr=NULL;
              if (pcp_book(pcp, new_eventid, &new_commit))
                     is_conflict=1;

              if (is_conflict)
              {
                     new_commit.event_times=save_times;
                     new_commit.n_event_times=n_save_times;
                     free(new_times);

                     if (conflict_list)
                     {
                            struct report_conflict_info *p;

                            for (p=conflict_list; p; p=p->next)
                            {
                                   char from_buf[15];
                                   char to_buf[15];

                                   pcp_gmtimestr(p->conflict_start,
                                                from_buf);
                                   pcp_gmtimestr(p->conflict_end, to_buf);

                                   printf("403%c%s %s %s %s conflicts.\n",
                                          p->next ? '-':' ',
                                          p->conflict_addr,
                                          from_buf,
                                          to_buf,
                                          p->conflict_eventid);
                            }
                     }
                     else
                     {
                            error(new_commit.errcode);
                     }
                     report_conflict_destroy(conflict_list);
              }
              else
              {
                     if (new_commit_times)
                            free(new_commit_times);
                     new_commit_times=new_times;
                     printf("200 Ok\n");
                     notbooked=0;
              }
              rebook_installtimeout(pcp);
       }

       while (list)
       {
              struct book_time_list *l=list;

              list=l->next;
              free(l);
       }

}

Here is the call graph for this function:

Here is the caller graph for this function:

static int doline ( struct PCP pcp,
char *  p,
int  acl_flags 
) [static]

Definition at line 1506 of file pcpd.c.

{
       char *q=strtok(p, " ");

       if (!q)
       {
              printf("500 Syntax error\n");
              return (0);
       }

       if (strcasecmp(q, "QUIT") == 0)
       {
              printf("200 Bye.\n");
              return (-1);
       }

       if (strcasecmp(q, "NOOP") == 0)
       {
              printf("200 Ok.\n");
              return (0);
       }

       if (strcasecmp(q, "CAPABILITY") == 0)
       {
              printf("100-ACL\n");
              printf("100 PCP1\n");
              return (0);
       }

       if (strcasecmp(q, "LIST") == 0)
       {
              if (check_acl(acl_flags, PCP_ACL_LIST))
                     return (0);

              if (list(pcp))
                     printf("500 Syntax error\n");
              return (0);
       }

       if (strcasecmp(q, "RETR") == 0)
       {
              if (check_acl(acl_flags, PCP_ACL_RETR))
                     return (0);

              if (retr(pcp))
                     printf("500 Syntax error\n");
              return (0);
       }


       if (strcasecmp(q, "ACL") == 0 && pcp_has_acl(pcp) && !proxy_userid)
       {
              q=strtok(NULL, " ");
              if (q && strcasecmp(q, "SET") == 0)
              {
                     const char *who=strtok(NULL, " ");

                     if (who)
                     {
                            int flags=0;

                            while ((q=strtok(NULL, " ")) != 0)
                                   flags |= pcp_acl_num(q);

                            if (pcp_acl(pcp, who, flags))
                            {
                                   error(0);
                                   return (0);
                            }
                            printf("200 Ok\n");
                            return (0);
                     }
              }
              else if (q && strcasecmp(q, "LIST") == 0)
              {
                     listacls(pcp);
                     return (0);
              }
       }

       if (strcasecmp(q, "RSET") == 0)
       {
              conflict_flag=0;
              force_flag=0;
              need_rset=0;
              rset(pcp);
              printf("200 Ok.\n"); 
              return (0);
       }

       if (need_rset)
       {
              printf("500 RSET required - calendar in an unknown state.\n");
              return (0);
       }

       if (strcasecmp(q, "DELETE") == 0)
       {
              struct PCP_retr r;
              const char *event_id_list[2];

              char *e=strtok(NULL, " ");

              if (check_acl(acl_flags, PCP_ACL_MODIFY))
                     return (0);

              if (e && deleted_eventid == NULL && new_eventid == NULL)
              {
                     if ((deleted_eventid=strdup(e)) == NULL)
                     {
                            perror("strdup");
                            exit(1);
                     }
                     proxy_list_rset();
                     memset(&r, 0, sizeof(r));
                     r.callback_retr_participants=open_event_participant;
                     event_id_list[0]=deleted_eventid;
                     event_id_list[1]=NULL;
                     r.event_id_list=event_id_list;
                     if (pcp_retr(pcp, &r))
                     {
                            error(r.errcode);
                            proxy_list_rset();
                     }
                     else
                            printf("200 Ok.\n");
                     return (0);
              }
       }

       if (strcasecmp(q, "NEW") == 0 && new_eventid == NULL)
       {
              if (check_acl(acl_flags, PCP_ACL_MODIFY))
                     return (0);

              new_eventid=readnewevent(pcp);

              if (new_eventid == NULL)
              {
                     printf("500 %s\n", strerror(errno));
              }
              else
                     printf("109 %s ready to be commited.\n",
                            new_eventid->eventid);
              return (0);
       }

       if (strcasecmp(q, "BOOK") == 0 && new_eventid)
       {
              dobook(pcp);
              return (0);
       }

       if (strcasecmp(q, "CONFLICT") == 0)
       {
              q=strtok(NULL, " ");
              if (q && strcasecmp(q, "ON") == 0)
              {
                     if (check_acl(acl_flags, PCP_ACL_CONFLICT))
                            return (0);

                     conflict_flag=1;
              }
              else
                     conflict_flag=0;
              printf("200 Ok.\n");
              return (0);
       }

       if (strcasecmp(q, "FORCE") == 0)
       {
              q=strtok(NULL, " ");
              if (q && strcasecmp(q, "ON") == 0)
              {
                     force_flag=1;
              }
              else
                     force_flag=0;
              printf("200 Ok.\n");
              return (0);
       }

       if (strcasecmp(q, "COMMIT") == 0)
       {
              if (notbooked)
              {
                     printf("500 BOOK required.\n");
              }
              else if (new_eventid && new_commit_times)
              {
                     struct proxy_list *pl;

                     new_commit.add_conflict_callback=NULL;
                     new_commit.add_conflict_callback_ptr=NULL;

                     new_commit.flags=
                            (conflict_flag ? PCP_OK_CONFLICT:0) |
                            (force_flag ? PCP_OK_PROXY_ERRORS:0);

                     for (pl=proxy_list; pl; pl=pl->next)
                     {
                            if (pl->flags & PROXY_IGNORE)
                                   continue;

                            if (pl->flags & PROXY_NEW)
                            {
                                   if (pcp_commit(pl->proxy,
                                                 pl->newevent,
                                                 &new_commit))
                                   {
                                          fprintf(stderr, "CRIT: "
                                                 "COMMIT failed for PROXY %s\n",
                                                 pl->userid);

                                          if (!force_flag)
                                          {
                                                 pl->flags &=
                                                        ~PROXY_NEW;
                                                 error(new_commit
                                                       .errcode);
                                                 return (0);
                                          }
                                   }
                            }
                            else if (pl->old_event_id)
                            {
                                   struct PCP_delete del;

                                   memset(&del, 0, sizeof(del));

                                   del.id=pl->old_event_id;

                                   if (pcp_delete(pl->proxy, &del))
                                   {
                                          fprintf(stderr, "CRIT: "
                                                 "DELETE failed for PROXY %s\n",
                                                 pl->userid);
                                          if (!force_flag)
                                          {
                                                 error(del.errcode);
                                                 return (0);
                                          }
                                          pl->flags |= PROXY_IGNORE;
                                   }
                            }
                     }

                     if (proxy_userid)
                            new_commit.flags |= PCP_BYPROXY;

                     if (pcp_commit(pcp, new_eventid, &new_commit))
                            error(new_commit.errcode);
                     else
                     {
                            const char *proxy_name=NULL;
                            const char *proxy_action=NULL;

                            for (pl=proxy_list; pl; pl=pl->next)
                            {
                                   if (proxy_name)
                                          printf("111-%s %s\n",
                                                 proxy_action,
                                                 proxy_name);

                                   proxy_action=
                                          !(pl->flags & PROXY_IGNORE)
                                          && (pl->flags & PROXY_NEW)
                                          ? "NEW":"DELETE";
                                   proxy_name=pl->userid;
                            }

                            if (proxy_name)
                                   printf("111 %s %s\n",
                                          proxy_action,
                                          proxy_name);
                            else
                                   printf("200 Ok.\n");
                     }      
                     rset(pcp);
                     return (0);
              }
              else if (!new_eventid && deleted_eventid)
              {
                     struct proxy_list *pl;
                     struct PCP_delete del;
                     const char *proxy_userid;

                     for (pl=proxy_list; pl; pl=pl->next)
                     {
                            if (pl->flags & PROXY_IGNORE)
                                   continue;

                            if (pl->old_event_id)
                            {
                                   memset(&del, 0, sizeof(del));
                                   del.id=pl->old_event_id;

                                   if (pcp_delete(pl->proxy, &del))
                                   {
                                          fprintf(stderr, "CRIT: "
                                                 "DELETE failed for PROXY %s\n",
                                                 pl->userid);
                                   }
                            }
                     }

                     memset(&del, 0, sizeof(del));
                     del.id=deleted_eventid;

                     if (pcp_delete(pcp, &del))
                     {
                            if (del.errcode != PCP_ERR_EVENTNOTFOUND)
                            {
                                   error(del.errcode);
                                   return (0);
                            }
                     }

                     proxy_userid=NULL;
                     for (pl=proxy_list; pl; pl=pl->next)
                     {
                            if (proxy_userid)
                                   printf("111-DELETE %s\n",
                                          proxy_userid);

                            proxy_userid=pl->userid;
                     }

                     if (proxy_userid)
                            printf("111 DELETE %s\n", proxy_userid);
                     else
                            printf("200 Ok\n");

                     rset(pcp);
                     return (0);
              }

              printf("500 There's nothing to commit.\n");
              return (0);
       }

       if (strcasecmp(q, "CANCEL") == 0)
       {
              int errcode;

              if (check_acl(acl_flags, PCP_ACL_MODIFY))
                     return (0);

              q=strtok(NULL, " ");
              if (!q)
                     printf("500 Syntax error\n");
              else if (pcp_cancel(pcp, q, &errcode))
                     error(errcode);
              else
                     printf("200 Cancelled\n");
              return (0);
       }

       if (strcasecmp(q, "UNCANCEL") == 0)
       {
              struct PCP_uncancel unc;
              struct uncancel_list *list=NULL, **tail= &list;
              struct uncancel_list *p;

              if (check_acl(acl_flags, PCP_ACL_MODIFY))
                     return (0);

              memset(&unc, 0, sizeof(unc));
              unc.uncancel_conflict_callback=uncancel_callback;
              unc.uncancel_conflict_callback_ptr=&tail;

              q=strtok(NULL, " ");
              if (!q)
                     printf("500 Syntax error\n");
              else if (pcp_uncancel(pcp, q,
                                  (conflict_flag ? PCP_OK_CONFLICT:0)|
                                  (force_flag ? PCP_OK_PROXY_ERRORS:0),
                                  &unc))
              {
                     if (unc.errcode == PCP_ERR_CONFLICT && list)
                     {
                            for (p=list; p; p=p->next)
                            {
                                   char from_buf[15];
                                   char to_buf[15];

                                   pcp_gmtimestr(p->from, from_buf);
                                   pcp_gmtimestr(p->to, to_buf);

                                   printf("403%c%s %s %s %s conflicts.\n",
                                          p->next ? '-':' ',
                                          p->addr,
                                          from_buf,
                                          to_buf,
                                          p->id);
                            }
                     }
                     else
                            error(unc.errcode);
              }
              else
                     printf("200 Uncancelled\n");

              while((p=list) != NULL)
              {
                     list=p->next;
                     free(p->addr);
                     free(p->id);
                     free(p);
              }
              return (0);
       }

       printf("500 Syntax error\n");
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void error ( int  n) [static]

Definition at line 226 of file pcpd.c.

{
        const char *p;

       switch (n) {
       case PCP_ERR_EVENTNOTFOUND:
              printf("504 Event not found\n");
              return;
       case PCP_ERR_EVENTLOCKED:
              printf("506 This event is temporarily locked\n");
              return;
       }

       p=pcp_strerror(n);

       printf("500 %s\n", p ? p:strerror(errno));
}

Here is the call graph for this function:

static int get_acl_callback ( const char *  w,
int  f,
void *  dummy 
) [static]

Definition at line 1960 of file pcpd.c.

{
       struct get_acl *ga=(struct get_acl *)dummy;

       if (addrcmp(w, ga->who) == 0)
              ga->flags=f;
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void inactive ( struct PCP p,
void *  dummy 
) [static]

Definition at line 64 of file pcpd.c.

{
       termsig=1;
}

Here is the caller graph for this function:

static int inputchar ( struct PCP pcp) [static]

Definition at line 69 of file pcpd.c.

{
       int c;

       while (inp_left == 0)
       {
              time_t new_time;
              struct timeval tv, *tvptr;
              fd_set fds;

              time(&new_time);

              /* Trigger any needed functions */

              while (first_timer &&
                     (new_time < prev_time - 30 ||
                     new_time >= first_timer->alarm))
              {
                     void (*func)(struct PCP *, void *)
                            =first_timer->handler;
                     void *arg=first_timer->voidarg;

                     pcpdtimer_triggered(first_timer);
                     (*func)(pcp, arg);
              }

              if (termsig)
                     return (EOF);
                     
              if (first_timer)
              {
                     tvptr= &tv;
                     tv.tv_sec=first_timer->alarm-new_time;
                     tv.tv_usec=0;
              }
              else
                     tvptr=NULL;

              /*
              ** Read more input.  piggy-back after the
              ** input buffer :-)
              */

              if (input_line_len + BUFSIZ >= input_buffer_len)
              {
                     size_t n=input_line_len + BUFSIZ;
                     char *p=realloc(input_buffer, n);

                     if (!p)
                     {
                            perror("realloc");
                            exit(1);
                     }
                     input_buffer=p;
                     input_buffer_len=n;
              }

              inp_ptr=input_buffer + input_line_len;

              FD_ZERO(&fds);
              FD_SET(0, &fds);

              if (fflush(stdout) || ferror(stdout))
              {
                     perror("write");
                     termsig=1;
                     return (EOF);
              }

              if (select(1, &fds, NULL, NULL, tvptr) < 0)
              {
                     if (termsig)
                            return (EOF);

                     if (errno != EINTR)
                     {
                            perror("select");
                            return (EOF);
                     }
                     inp_left=0;
                     continue;
              }

              if (!FD_ISSET(0, &fds))
                     continue;

              inp_left=read(0, inp_ptr, BUFSIZ);

              if (termsig || inp_left == 0)
              {
                     termsig=1;
                     return (EOF);
              }

              if (inp_left < 0)
              {
                     perror("read");
                     return (EOF);
              }
       }

       c= *inp_ptr++;
       --inp_left;
       return ((int)(unsigned char)c);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int list ( struct PCP pcp) [static]

Definition at line 1022 of file pcpd.c.

{
       struct list_struct ls;
       const char *q;
       struct list_item *e;

       memset(&ls, 0, sizeof(ls));
       ls.list_info.callback_arg= &ls;
       ls.list_info.callback_func= &list_callback;
       ls.last_event= &ls.event_list;

       while ((q=strtok(NULL, " ")) != NULL)
       {
              if (strcasecmp(q, "FROM") == 0)
              {
                     char buf[15];

                     q=strtok(NULL, " ");
                     if (!q)
                            return (-1);
                     if (ls.list_info.list_from ||
                         ls.list_info.list_to)
                            return (-1);

                     if (*q != '-')
                     {
                            if (strlen(q) < 14)
                                   return (-1);
                            memcpy(buf, q, 14);
                            buf[14]=0;
                            q += 14;
                            if ((ls.list_info.list_from
                                 =pcp_gmtime_s(buf)) == 0)
                                   return (-1);
                     }
                     if (*q)
                     {
                            if (*q++ != '-' || strlen(q) != 14)
                                   return (-1);
                            memcpy(buf, q, 14);
                            buf[14]=0;
                            q += 14;
                            if ((ls.list_info.list_to
                                 =pcp_gmtime_s(buf)) == 0)
                                   return (-1);
                     }
              }
       }

       if (pcp_list_all(pcp, &ls.list_info))
       {
              error(0);
       }
       else
       {
              for (e=ls.event_list; e; e=e->next)
              {
                     char from_buf[15], to_buf[15];

                     pcp_gmtimestr(e->start, from_buf);
                     pcp_gmtimestr(e->end, to_buf);

                     printf("105%c%s %s %s event found.\n",
                            e->next ? '-':' ',
                            e->event_id,
                            from_buf,
                            to_buf);
              }

              if (ls.event_list == NULL)
                     printf("504 event-id not found.\n");
       }

       while ((e=ls.event_list) != NULL)
       {
              ls.event_list=e->next;
              free(e->event_id);
              free(e);
       }
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int list_acl_callback ( const char *  who,
int  flags,
void *  dummy 
) [static]

Definition at line 1412 of file pcpd.c.

{
       struct acl_list **p=(struct acl_list **)dummy;
       struct acl_list *q=malloc(sizeof(struct acl_list));

       if (!q)
              return (-1);
       if ((q->who=strdup(who)) == NULL)
       {
              free(q);
              return (-1);
       }
       q->flags=flags;
       q->next= *p;
       *p=q;
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int list_callback ( struct PCP_list_all p,
void *  vp 
) [static]

Definition at line 998 of file pcpd.c.

{
       struct list_struct *ls=(struct list_struct *)vp;
       char *s=strdup(p->event_id);

       if (!s)
              return (-1);

       if ( ((*ls->last_event)=(struct list_item *)
             malloc(sizeof(struct list_item))) == NULL)
       {
              free(s);
              return (-1);
       }

       (*ls->last_event)->event_id=s;
       (*ls->last_event)->start=p->event_from;
       (*ls->last_event)->end=p->event_to;
       (*ls->last_event)->next=NULL;

       ls->last_event= & (*ls->last_event)->next;
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void listacls ( struct PCP pcp) [static]

Definition at line 1430 of file pcpd.c.

{
       char buf[1024];
       struct acl_list *list=NULL;
       struct acl_list *p;

       if (pcp_list_acl(pcp, list_acl_callback, &list) == 0)
       {
              if (list == NULL)
                     printf("203 Empty ACL\n");
              else
              {
                     for (p=list; p; p=p->next)
                     {
                            buf[0]=0;
                            pcp_acl_name(p->flags, buf);
                            printf("103%c%s %s\n",
                                   p->next ? '-':' ',
                                   p->who, buf);
                     }
              }
       }
       else error(0);

       while ((p=list) != NULL)
       {
              list=p->next;
              free(p->who);
              free(p);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char * login ( int  isprivate,
int *  flag 
) [static]

Definition at line 2365 of file pcpd.c.

{
       struct userid_info uinfo;

       proxy_userid=NULL;
       *flag=0;
       memset(&uinfo, 0, sizeof(uinfo));
       alarm(300);   /* Better log in in five minutes */
       for (;;)
       {
              int c;
              char *p;

              input_line_len=0;
              for (;;)
              {
                     c=inputchar(NULL);
                     if (c == EOF)
                            exit(0);

                     if (c == '\n')
                            break;
                     input_buffer[input_line_len]=c;
                     if (input_line_len < 1024)
                            ++input_line_len;
              }
              input_buffer[input_line_len]=0;

              for (p=input_buffer; *p &&
                          isspace((int)(unsigned char)*p); p++)
                     ;

              if (strncasecmp(p, "PASSWORD", 8) == 0 && !isprivate &&
                  isspace((int)(unsigned char)p[8]) && uinfo.userid)
              {
                     for (p += 9; isspace((int)(unsigned char)*p); p++)
                            ;

                     if (*p)
                     {
                            int rc;
                            char *q, *r;

                            for (q=r=p; *q; q++)
                                   if (!isspace((int)(unsigned char)*q))
                                          r=q+1;
                            *r=0;

                            rc=authpcp_login(uinfo.userid, p,
                                           callback_login, &uinfo);

                            if (rc)
                            {
                                   printf("%s %s\n",
                                          rc < 0 ? "501":"401",
                                          strerror(errno));
                                   continue;
                            }
                            *flag=1;
                            break;
                     }
              }

              for (p=input_buffer; *p; p++)
                     if (isspace((int)(unsigned char)*p))
                            *p=' ';

              p=strtok(input_buffer, " ");

              if (p && strcasecmp(p, "CAPABILITY") == 0)
              {
                     printf("100 PCP1\n");
                     continue;
              }
              else if (p && strcasecmp(p, "USERID") == 0 &&
                  uinfo.userid == NULL)
              {
                     if ((p=strtok(NULL, " ")) != NULL)
                     {
                            int rc= authpcp_userid(p, callback_userid,
                                                 &uinfo);

                            if (rc)
                            {
                                   printf("%s %s\n",
                                          rc < 0 ? "501":"401",
                                          strerror(errno));
                                   continue;
                            }

                            printf("301 Ok, waiting for password.\n");
                            continue;
                     }
              }
              else if (p && strcasecmp(p, "PROXY") == 0 && uinfo.userid &&
                      isprivate)
              {
                     if ((p=strtok(NULL, " ")) != 0)
                     {
                            struct relogin_struct rs;
                            time_t now;
                            int rc;

                            if (proxy_userid)
                                   free(proxy_userid);
                            if ((proxy_userid=auth_choplocalhost(p))
                                == NULL)
                            {
                                   printf("400 %s\n", strerror(errno));
                                   continue;
                            }

                            rs.needauthtoken=0;
                            rs.userid=uinfo.userid;

                            time(&now);

                            rc=maildir_cache_search(uinfo.userid, now,
                                                 callback_cache_search,
                                                 &rs);
                            if (rc == 0)
                            {
                                   alarm(0);
                                   printf("200 PROXY ok\n");
                                   break;
                            }
                            now -= TIMEOUT;

                            rc=maildir_cache_search(uinfo.userid, now,
                                                 callback_cache_search,
                                                 &rs);
                            if (rc == 0)
                            {
                                   alarm(0);
                                   printf("200 PROXY ok\n");
                                   break;
                            }

                            uinfo.isproxy=1;
                            rc=authpcp_userid(uinfo.userid, callback_login,
                                            &uinfo);
                            if (rc)
                            {
                                   fprintf(stderr,
                                          "CRIT: auth_userid() failed\n");
                                   exit(1);
                            }
                            alarm(0);
                            printf("200 PROXY ok\n");
                            break;
                     }

              }
              else if (p && strcasecmp(p, "RELOGIN") == 0 && uinfo.userid &&
                      !isprivate)
              {
                     if ((p=strtok(NULL, " ")) != 0)
                     {
                            struct relogin_struct rs;
                            int rc;

                            rs.needauthtoken=1;
                            rs.userid=uinfo.userid;
                            if (authtoken_verify(uinfo.userid, p,
                                               &rs.when))
                            {
                                   printf("500 Invalid authentication token.\n");
                                   continue;
                            }

                            rc=maildir_cache_search(uinfo.userid, rs.when,
                                                 callback_cache_search,
                                                 &rs);
                            if (rc == 0)
                                   break;

                            /*
                            ** Couldn't find anything in the login cache.
                            ** call the userid function with the login
                            ** callback.
                            ** This'll initialize lotsa other stuff, but
                            ** we don't care.
                            */

                            rc=authpcp_userid(uinfo.userid,
                                            callback_login,
                                            &uinfo);

                            if (rc)
                            {
                                   fprintf(stderr,
                                          "NOTICE: auth_userid() failed.\n");
                                   printf("400 Internal failure - try again later.\n");
                                   continue;
                            }
                            break;
                     }
              }
              else if (p && strcasecmp(p, "QUIT") == 0)
              {
                     printf("200 Ok\n");
                     exit (0);
              }
              printf("500 Syntax error\n");
       }
       return (uinfo.userid);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int main ( int  argc,
char **  argv 
)

Definition at line 2575 of file pcpd.c.

{
       int argn=1;
       static const char * const authvars[]={NULL};

       signal(SIGPIPE, SIG_IGN);
       umask(022);

       if (argn >= argc)
       {
              struct PCP *pcp;

              pcp=open_calendar(NULL);

              mainloop(pcp);
              exit(0);
       }

       maildir_cache_init(TIMEOUT * 2, CACHEDIR, LOCALCACHEOWNER, authvars);

       if (strcmp(argv[argn], "server") == 0)
       {
              struct group *gr;

              if (chdir(CALENDARDIR) < 0)
              {
                     perror(CALENDARDIR);
                     exit(1);
              }
              gr=getgrnam(MAILGROUP);

              if (!gr)
              {
                     fprintf(stderr, "Unknown group: %s\n", MAILGROUP);
                     exit(1);
              }

              authtoken_init();
              libmail_changeuidgid(getuid(), gr->gr_gid);
              start();
       }
       else if (strcmp(argv[argn], "login") == 0 ||
               strcmp(argv[argn], "slogin") == 0)
       {
              struct PCP *pcp;
              int flag;
              struct group *gr;

              gr=getgrnam(MAILGROUP);

              if (!gr)
              {
                     fprintf(stderr, "Unknown group: %s\n", MAILGROUP);
                     exit(1);
              }
              libmail_changeuidgid(getuid(), gr->gr_gid);

              if (chdir(CALENDARDIR) < 0)
              {
                     perror(CALENDARDIR);
                     exit(1);
              }

              authtoken_init();
              userid=login(strcmp(argv[argn], "login"), &flag);

              pcp=pcp_open_dir(".", userid);

              if (pcp && flag && pcp_cleanup(pcp))
              {
                     pcp_close(pcp);
                     fprintf(stderr, "CRIT: pcp_cleanup failed\n");
                     pcp=NULL;
              }

              if (!pcp)
              {
                     fprintf(stderr, "CRIT: pcp_open_dir failed\n");
                     perror("pcp_open_dir");
                     exit(1);
              }

              mainloop(pcp);
              exit(0);
       }
       else if (strcmp(argv[argn], "open") == 0)
       {
              ++argn;
              if (argn < argc)
              {
                     struct PCP *pcp;

                     pcp=open_calendar(argv[argn]);

                     mainloop(pcp);
                     exit(0);
              }
       }
       fprintf(stderr, "Usage: %s (server|open [path])\n", argv[0]);
       exit(0); /* exit(1) breaks Courier rpm %preun script */
       return (0);
}

Here is the call graph for this function:

static void mainloop ( struct PCP pcp) [static]

Definition at line 1969 of file pcpd.c.

{
       int c;
       struct pcpdtimer inactivity_timeout;
       int my_acl_flags=PCP_ACL_MODIFY|PCP_ACL_CONFLICT|
              PCP_ACL_LIST|PCP_ACL_RETR;

       deleted_eventid=NULL;
       memset(&new_commit, 0, sizeof(new_commit));
       new_commit_times=NULL;
       new_commit_participants=NULL;
       new_commit_participants_buf=NULL;

       termsig=0;

       setsigs();

       inp_ptr=0;
       inp_left=0;
       need_rset=0;

       time(&prev_time);

       pcpdtimer_init(&inactivity_timeout);
       inactivity_timeout.handler=inactive;

       if (proxy_userid)
       {
              struct get_acl ga;

              ga.who=proxy_userid;
              ga.flags=0;
              if (pcp_has_acl(pcp))
              {
                     if (pcp_list_acl(pcp, get_acl_callback, &ga) == 0)
                     {
                            if (ga.flags == 0)
                            {
                                   ga.who="public";
                                   if (pcp_list_acl(pcp, get_acl_callback,
                                                  &ga))
                                          ga.flags=0;
                            }
                     }
                     else ga.flags=0;
              }
              my_acl_flags=ga.flags;
       }

       do
       {
              char *p;

              input_line_len=0;
              pcpdtimer_install(&inactivity_timeout, 30 * 60);

              for (;;)
              {


                     c=inputchar(pcp);

                     if (termsig || c == '\n')
                            break;
                     input_buffer[input_line_len++]=c;
              }
              if (termsig)
                     break;

              input_buffer[input_line_len]=0;

              for (p=input_buffer; *p; p++)
                     if (isspace((int)(unsigned char)*p))
                            *p=' ';
              pcpdtimer_triggered(&inactivity_timeout);
              /* Cancel inactivity_timeout for the duration of the command */

       } while (doline(pcp, input_buffer, my_acl_flags) == 0 && !termsig);
       alarm(0);
       free(input_buffer);
       rset(pcp);
}

Here is the call graph for this function:

static int mkparticipants ( struct PCP_save_event se) [static]

Definition at line 489 of file pcpd.c.

{
       struct proxy_list *p;
       unsigned cnt;
       size_t l=0;

       if (new_commit_participants)
              free(new_commit_participants);
       if (new_commit_participants_buf)
              free(new_commit_participants_buf);
       new_commit_participants=NULL;
       new_commit_participants_buf=NULL;

       se->event_participants=NULL;
       se->n_event_participants=0;

       for (cnt=0, p=proxy_list; p; p=p->next)
       {
              if (!p->newevent)
                     continue;

              if (p->flags & PROXY_IGNORE)
                     continue;

              ++cnt;
              l += strlen(p->userid)+1;

              if (p->newevent->eventid)
                     l += strlen(p->newevent->eventid)+1;
       }
       if (cnt == 0)
              return (0);

       if ((new_commit_participants_buf=malloc(l)) == NULL)
              return (-1);
       if ((new_commit_participants
            =calloc(cnt, sizeof(struct PCP_event_participant))) == NULL)
              return (-1);

       l=0;

       for (cnt=0, p=proxy_list; p; p=p->next)
       {
              if (!p->newevent)
                     continue;

              if (p->flags & PROXY_IGNORE)
                     continue;

              new_commit_participants[cnt].address=
                     strcpy(new_commit_participants_buf+l, p->userid);
              l += strlen(p->userid)+1;

              if (p->newevent->eventid)
              {
                     new_commit_participants[cnt].eventid=
                            strcpy(new_commit_participants_buf+l,
                                   p->newevent->eventid);
                     l += strlen(p->newevent->eventid)+1;
              }
              ++cnt;
       }
       se->event_participants=new_commit_participants;
       se->n_event_participants=cnt;
       return (0);
}

Here is the caller graph for this function:

struct PCP* open_calendar ( const char *  p) [read]

Definition at line 177 of file pcpd.c.

{
        struct PCP *pcp;
        struct passwd *pw=getpwuid(getuid());
        const char *cp;

        if (!pw)
        {
                perror("getpwuid");
                exit(1);
        }

       userid=strdup(pw->pw_name);

        if (p && *p)
       {
              if (chdir(p))
              {
                     perror(p);
                     exit(1);
              }
       }
        else if ((cp=getenv("PCPDIR")) != NULL && *cp)
        {
              if (chdir(cp))
              {
                     perror(cp);
                     exit(1);
              }
        }

       pcp=pcp_open_dir(".", userid);

       if (pcp && pcp_cleanup(pcp))
       {
              pcp_close(pcp);
              pcp=NULL;
       }

       if (!pcp)
       {
              perror("pcp_open_dir");
              exit(1);
       }
       return (pcp);
}

Here is the call graph for this function:

static int open_event_participant ( struct PCP_retr r,
const char *  n,
const char *  id,
void *  vp 
) [static]

Definition at line 1462 of file pcpd.c.

{
       struct proxy_list *p;
       char *errmsg;

       if (proxy_userid)
       {
              printf("500-Cannot create proxy in proxy mode.\n");
              errno=EIO;
              return (-1);
       }

       p=proxy(n, &errmsg);

       if (p)
       {
              if ((p->old_event_id=strdup(id)) == NULL)
                     return (-1);
              return (0);
       }

       if (!force_flag)
       {
              if (errmsg)
              {
                     proxy_error(n, errmsg);
                     free(errmsg);
              }
              errno=EIO;
              return (-1);
       }
       if (errmsg)
              free(errmsg);

       p->flags |= PROXY_IGNORE;
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct proxy_list* proxy ( const char *  proxy_userid,
char **  errmsg 
) [static, read]

Definition at line 324 of file pcpd.c.

{
       struct proxy_list *p;

       if (errmsg)
              *errmsg=0;

       for (p=proxy_list; p; p=p->next)
       {
              if (addrcmp(proxy_userid, p->userid) == 0)
                     return (p);
       }

       p=malloc(sizeof(struct proxy_list));
       if (!p)
              return (NULL);
       memset(p, 0, sizeof(*p));

       if ((p->userid=strdup(proxy_userid)) == NULL)
       {
              free(p);
              return (NULL);
       }

       if ((p->proxy=pcp_find_proxy(proxy_userid, NULL, errmsg)) == NULL ||
           pcp_set_proxy(p->proxy, userid))
       {
              if (p->proxy)
                     pcp_close(p->proxy);
              free(p->userid);
              free(p);
              return (NULL);
       }

       p->next=proxy_list;
       proxy_list=p;
       return (p);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void proxy_error ( const char *  n,
const char *  msg 
) [static]

Definition at line 468 of file pcpd.c.

{
       while (*msg)
       {
              printf("500-%s - ", n);
              while (*msg)
              {
                     if (*msg == '\n')
                     {
                            ++msg;
                            break;
                     }
                     if (*msg != '\r')
                            putchar( *msg);
                     ++msg;
              }
              printf("\n");
       }

}

Here is the caller graph for this function:

static void proxy_list_rset ( ) [static]

Definition at line 261 of file pcpd.c.

{
       struct proxy_list *p;

       while ((p=proxy_list) != NULL)
       {
              proxy_list=p->next;
              if (p->newevent)
                     pcp_destroy_eventid(p->proxy, p->newevent);
              pcp_close(p->proxy);
              free(p->userid);
              if (p->old_event_id)
                     free(p->old_event_id);
              proxy_list=p->next;
              free(p);
       }
}

Here is the caller graph for this function:

static struct PCP_new_eventid* readnewevent ( struct PCP pcp) [static, read]

Definition at line 556 of file pcpd.c.

{
       struct PCP_save_event se;
       struct readnewevent_s rne;
       struct PCP_new_eventid *ne;
       const char *cp;
       struct proxy_list *p;
       int first_save=1;

       memset(&rne, 0, sizeof(rne));
       if (!deleted_eventid)
              proxy_list_rset();

       /* Open new proxy connections */

       while ((cp=strtok(NULL, " ")) != NULL)
       {
              char *errmsg, *q;
              char *n=strdup(cp);
              struct proxy_list *pcp;

              if (!n)
              {
                     fprintf(stderr, "ALERT: Out of memory.\n");
                     exit(1);
              }

              if (proxy_userid)
              {
                     printf("500-Cannot create proxy in proxy mode.\n");
                     free(n);
                     errno=EIO;
                     return (NULL);
              }

              strcpy(n, cp);
              pcp=proxy(n, &errmsg);

              if (pcp)
              {
                     pcp->flags |= PROXY_NEW;
                     free(n);
                     continue;
              }

              if (force_flag)
              {
                     pcp->flags |= PROXY_IGNORE;
                     free(n);
                     continue;
              }

              while (errmsg && (q=strchr(errmsg, '\n')) != 0)
                     *q='/';
              printf("500-%s: %s\n", n, errmsg ? errmsg:"Failed to create a proxy connection.");
              free(n);
              proxy_list_rset();
              return (NULL);
       }

       memset(&se, 0, sizeof(se));
       if ((rne.tmpfile=tmpfile()) == NULL)
              return (NULL);
       time(&rne.last_noop_time);

       rne.seeneol=1;
       rne.seendot=0;
       rne.seeneof=0;
       rne.cnt=0;
       rne.pcp=pcp;
       pcpdtimer_init(&rne.inactivity_timeout);
       rne.inactivity_timeout.handler=&inactive;
       pcpdtimer_install(&rne.inactivity_timeout, 300);

       for (p=proxy_list; p; p=p->next)
       {
              struct PCP_save_event se;

              if ( !(p->flags & PROXY_NEW))
                     continue;

              if (fseek(rne.tmpfile, 0L, SEEK_SET) < 0
                  || lseek(fileno(rne.tmpfile), 0L, SEEK_SET) < 0)
              {
                     int save_errno=errno;
                     proxy_list_rset();
                     pcpdtimer_triggered(&rne.inactivity_timeout);
                     fclose(rne.tmpfile);
                     errno=save_errno;
                     return (NULL);
              }

              memset(&se, 0, sizeof(se));
              if (first_save)
              {
                     se.write_event_func_misc_ptr= &rne;
                     se.write_event_func=readnewevent_callback;
              }
              else
                     se.write_event_fd=fileno(rne.tmpfile);

              if ((p->newevent=pcp_new_eventid(p->proxy,
                                           p->old_event_id,
                                           &se)) == NULL)
              {
                     pcpdtimer_triggered(&rne.inactivity_timeout);

                     if (force_flag)
                     {
                            /* Force it through */

                            p->flags &= ~PROXY_NEW;
                            p->flags |= PROXY_IGNORE;
                            continue;
                     }

                     proxy_error(p->userid,
                                pcp_errmsg(p->proxy));
                     proxy_list_rset();
                     fclose(rne.tmpfile);
                     errno=EIO;
                     return (NULL);
              }
              if (first_save)
                     pcpdtimer_triggered(&rne.inactivity_timeout);
              first_save=0;
       }


       if (first_save)
       {
              se.write_event_func_misc_ptr= &rne;
              se.write_event_func=readnewevent_callback;
       }
       else
              se.write_event_fd=fileno(rne.tmpfile);

       if (mkparticipants(&se) || fseek(rne.tmpfile, 0L, SEEK_SET) < 0
           || lseek(fileno(rne.tmpfile), 0L, SEEK_SET) < 0)
       {
              int save_errno=errno;

              proxy_list_rset();
              fclose(rne.tmpfile);
              errno=save_errno;
              return (NULL);
       }

       if ((ne=pcp_new_eventid(pcp, deleted_eventid, &se)) == NULL)
       {
              while (!rne.seeneof)
              {
                     char buf[512];

                     readnewevent_callback(buf, sizeof(buf), &se);
              }
       }
       pcpdtimer_triggered(&rne.inactivity_timeout);
       if (first_save)
       {
              if (fflush(rne.tmpfile) || ferror(rne.tmpfile))
              {
                     int save_errno=errno;

                     proxy_list_rset();
                     fclose(rne.tmpfile);
                     errno=save_errno;
                     return (NULL);
              }
       }

       notbooked=1;
       fclose(rne.tmpfile);
       return (ne);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int readnewevent_callback ( char *  p,
int  n,
void *  vp 
) [static]

Definition at line 402 of file pcpd.c.

{
       struct readnewevent_s *rne=(struct readnewevent_s *)vp;
       int cnt=0;

       if (!rne->sentprompt)
       {
              rne->sentprompt=1;
              printf("300 Send event text, terminate by a line with a single dot.\n");
       }

       while (!rne->seeneof && n)
       {
              int c=inputchar(rne->pcp);

              if (c == EOF)
              {
                     rne->seeneof=1;
                     errno=ETIMEDOUT;
                     return (-1);
              }

              if (c == '\r')
                     continue;

              if (c == '\n')
              {
                     if (rne->seendot)
                            rne->seeneof=1;
                     rne->seendot=0;
                     rne->seeneol=1;
                     if (rne->seeneof)
                            continue;
              }
              else
              {
                     rne->seendot= c == '.' && rne->seeneol;
                     rne->seeneol=0;
                     if (rne->seendot)
                            continue;
              }
              putc(c, rne->tmpfile);
              ++cnt;
              *p++ = c;
              --n;

              if (++rne->cnt >= 8192)
              {
                     time_t t;

                     time(&t);
                     if (t >= rne->last_noop_time+300) /* Don't timeout */
                     {
                            struct proxy_list *p;
                            rne->last_noop_time=t;
                            for (p=proxy_list; p; p=p->next)
                                   pcp_noop(p->proxy);
                     }

                     pcpdtimer_install(&rne->inactivity_timeout, 300);
                     rne->cnt=0;
              }
       }
       return (cnt);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void rebook ( struct PCP pcp,
void *  vp 
) [static]

Definition at line 809 of file pcpd.c.

{
       struct proxy_list *p;

       pcp_noop(pcp);

       for (p=proxy_list; p; p=p->next)
              pcp_noop(p->proxy);
       rebook_installtimeout(pcp);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void rebook_installtimeout ( struct PCP pcp) [static]

Definition at line 803 of file pcpd.c.

{
       rebook_timeout.handler=rebook;
       pcpdtimer_install(&rebook_timeout, 15 * 60);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void report_conflict_destroy ( struct report_conflict_info p) [static]

Definition at line 788 of file pcpd.c.

{
       struct report_conflict_info *q;

       while ((q=p) != 0)
       {
              p=q->next;
              free(q->conflict_addr);
              free(q->conflict_eventid);
              free(q);
       }
}

Here is the caller graph for this function:

static int retr ( struct PCP pcp) [static]

Definition at line 1256 of file pcpd.c.

{
       struct PCP_retr r;
       struct retrinfo ri;
       const char *q;
       int n;
       struct retrinfo_event_list *p;

       memset(&r, 0, sizeof(r));
       memset(&ri, 0, sizeof(ri));

       r.callback_arg= &ri;

       for (;;)
       {
              if ((q=strtok(NULL, " ")) == NULL)
                     return (-1);

              if (strcasecmp(q, "EVENTS") == 0)
                     break;

              if (strcasecmp(q, "TEXT") == 0)
              {
                     r.callback_begin_func=callback_retr_begin;
                     r.callback_rfc822_func=callback_retr_message;
                     r.callback_end_func=callback_retr_end;
                     continue;
              }

              if (strcasecmp(q, "HEADERS") == 0)
              {
                     r.callback_begin_func=callback_retr_begin;
                     r.callback_headers_func=callback_retr_headers;
                     r.callback_end_func=callback_retr_end;
                     continue;
              }

              if (strcasecmp(q, "DATE") == 0)
              {
                     r.callback_retr_date=callback_retr_date;
                     continue;
              }

              if (strcasecmp(q, "ADDR") == 0)
              {
                     r.callback_retr_participants=
                            callback_retr_participants;
                     continue;
              }

              if (strcasecmp(q, "STATUS") == 0)
              {
                     r.callback_retr_status=callback_retr_status;
                     continue;
              }
              return (-1);
       }

       if (r.callback_headers_func && r.callback_rfc822_func)
              return (-1);

       n=0;
       while ((q=strtok(NULL, " ")) != NULL)
       {
              char *s=strdup(q);

              if (!s || (p=malloc(sizeof(struct retrinfo_event_list)))
                  == NULL)
              {
                     perror("malloc");
                     exit(1);
              }
              p->event_id=s;
              p->next=ri.event_list;
              ri.event_list=p;
              ++n;
       }

       if (ri.event_list == NULL)
              return (-1);

       if ((ri.event_list_array=malloc((n+1) * sizeof(const char *)))
           == NULL)
       {
              perror("malloc");
              exit(1);
       }

       n=0;
       for (p=ri.event_list; p; p=p->next)
              ri.event_list_array[n++]=p->event_id;
       ri.event_list_array[n]=0;

       r.event_id_list=ri.event_list_array;

       if (pcp_retr(pcp, &r))
              error(r.errcode);
       else
              printf("108 RETR complete\n");

       while ((p=ri.event_list) != 0)
       {
              ri.event_list=p->next;
              free(p->event_id);
              free(p);
       }
       free(ri.event_list_array);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void rset ( struct PCP pcp) [static]

Definition at line 365 of file pcpd.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void setsigs ( ) [static]

Definition at line 1943 of file pcpd.c.

{
       struct sigaction sa;

       memset(&sa, 0, sizeof(sa));

       sa.sa_handler=catch_sig;
       sigaction(SIGHUP, &sa, NULL);
       sigaction(SIGTERM, &sa, NULL);
       sigaction(SIGINT, &sa, NULL);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void start ( ) [static]

Definition at line 2058 of file pcpd.c.

{
       int pubsock;
       int privsock;

       if ((pubsock=pcp_mksocket(PUBDIR, "PCPDLOCAL")) < 0)
       {
              exit(1);
       }

       if ((privsock=pcp_mksocket(PRIVDIR, "PCPDLOCAL")) < 0)
       {
              exit (1);
       }

#if USE_NOCLDWAIT
       {
              struct sigaction sa;

              memset(&sa, 0, sizeof(sa));
              sa.sa_handler=SIG_IGN;
              sa.sa_flags=SA_NOCLDWAIT;
              sigaction(SIGCHLD, &sa, NULL);
       }
#else
       signal(SIGCHLD, SIG_IGN);
#endif

       for (;;)
       {
              fd_set fds;
              struct timeval tv;
              int rc;

              FD_ZERO(&fds);
              FD_SET(pubsock, &fds);
              FD_SET(privsock, &fds);

              tv.tv_sec=authtoken_check();
              tv.tv_usec=0;

              if ((rc=select ( (pubsock > privsock ? pubsock:privsock)+1,
                             &fds, NULL, NULL, &tv)) < 0)
              {
                     perror("pcpd: select");
                     continue;
              }

              if (rc == 0)
                     continue;

              if (FD_ISSET(pubsock, &fds))
                     accept_pcpd(pubsock, pubsock, privsock, 0);

              if (FD_ISSET(privsock, &fds))
                     accept_pcpd(privsock, pubsock, privsock, 1);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int uncancel_callback ( const char *  event,
time_t  from,
time_t  to,
const char *  addr,
void *  vp 
) [static]

Definition at line 1375 of file pcpd.c.

{
       struct uncancel_list ***tail_ptr=(struct uncancel_list ***)vp;
       struct uncancel_list **tail= *tail_ptr;
       char *s=strdup(event);
       char *a=strdup(addr);
       struct uncancel_list *newptr;

       if (!s || !a || (newptr=(struct uncancel_list *)
                      malloc(sizeof(struct uncancel_list))) == NULL)
       {
              if (a) free(a);
              if (s) free(s);
              return (-1);
       }

       newptr->addr=a;
       newptr->id=s;
       newptr->from=from;
       newptr->to=to;

       *tail=newptr;
       newptr->next=0;

       *tail_ptr= &(*tail)->next;
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

int conflict_flag [static]

Definition at line 43 of file pcpd.c.

char* deleted_eventid [static]

Definition at line 41 of file pcpd.c.

int force_flag [static]

Definition at line 44 of file pcpd.c.

int inp_left [static]

Definition at line 62 of file pcpd.c.

char* inp_ptr [static]

Definition at line 61 of file pcpd.c.

char* input_buffer = NULL [static]

Definition at line 57 of file pcpd.c.

size_t input_buffer_len = 0 [static]

Definition at line 58 of file pcpd.c.

size_t input_line_len [static]

Definition at line 59 of file pcpd.c.

int need_rset [static]

Definition at line 56 of file pcpd.c.

Definition at line 49 of file pcpd.c.

Definition at line 50 of file pcpd.c.

struct PCP_event_time* new_commit_times [static]

Definition at line 48 of file pcpd.c.

struct PCP_new_eventid* new_eventid [static]

Definition at line 42 of file pcpd.c.

int notbooked [static]

Definition at line 45 of file pcpd.c.

struct PCP_commit [static]

Definition at line 47 of file pcpd.c.

struct pcpdtimer [static]

Definition at line 52 of file pcpd.c.

time_t prev_time [static]

Definition at line 60 of file pcpd.c.

Definition at line 259 of file pcpd.c.

char* proxy_userid [static]

Definition at line 40 of file pcpd.c.

int termsig [static]

Definition at line 54 of file pcpd.c.

char* userid [static]

Definition at line 39 of file pcpd.c.