/*

  area manager for gtic, experimental, 17 March 1998
	updated 27 May 1998
	
  accepts standard rfc message via stdin
  should be sgid to somegroup for writing to areas_file and users_file
	[also read INSTALL file please]
  usually called by MTA from /etc/aliases:
    filefix: "|/path/gtic -m"

*/

#include <stdio.h>
#include <string.h>

#include "config.h"

void swap_uid_gid();

void area_manager(void)
{
  node_t addr;
	char *from=NULL,*subj=NULL,*ftn,*ro_ftn,*tmp,*p,*real_address=NULL;
  user_t *user; int i; list_t *ltmp; area_t *atmp;
	int strtonode_res;
  FILE *resp_fp,*help_fp;
  char buff[BUFSIZE];

  /* find From and Subject */
  while(1)
  {
    if(fgets(buff,sizeof(buff)-1,stdin)==NULL) break;
    delcrlf(buff);

		/* accept correct RFC message - \n at end of headers */
		if(buff[0]==0) break;
		
    if(!strncmp(buff,"From: ",6))
    {
      if(!from)
			{
				if(strchr(buff,'<') && strchr(buff,'>'))
				{
					from=xstrcpy(strchr(buff,'<')+1);
					if(strchr(from,'>'))
						strchr(from,'>')[0]=0;
				}
				else
				{
	        from=xstrcpy(buff+6);
				}
			}
    }
    else if(!strncmp(buff,"Subject: ",9))
    {
      subj=xstrcpy(buff+9);

			subj=xstrcpy(strtok(buff+9," \t"));

			/* xstrcpy return NULL when parameter is NULL -> all ok */
			real_address=xstrcpy(strtok(NULL," \t"));

			/* TODO: work with non-RFC address here! */
			
/*      break; don't break here */
    }
  }
  
  if(from==NULL)
  {
    l_printf("no From in area_manager");
    return;
  }
  if(subj==NULL)
  {
    l_printf("no Subject in area_manager (From=%s)",from);
		/* TODO: write response about "no subject" here */
    return;
  }
  /* determine rfc-ftn-address and convert it to ftn-address */
  if(strchr(from,'@')==NULL && strchr(from,'!')==NULL)
  {
		/* TODO: work with $HOSTNAME here */
    l_printf("incorrect address in area_manager (From=%s)",from);
    return;
  }

	if(real_address==NULL)
	{
		if(strchr(from,'@'))
			real_address=strchr(from,'@')+1;
		else
			real_address=strchr(from,'!')+1;
	}
		
	if((strtonode_res=strtonode(&addr,real_address,NULL))!=0)
	{
		l_printf("parse error in address \"%s\" (%d)\n",
			from,strtonode_res);
/*		return; */
	}
/*printf("DBG: %d:%d/%d.%d\n",addr.zone,addr.net,addr.node,addr.point);
*/
  ftn=xstrcpy(nodetoftn(NULL,&addr));
  ro_ftn=xstrcat("!",xstrcpy(ftn));

  if(response_exec)
  {
    tmp=xstrcpy(response_exec);
    tmp=xstrcat(tmp," \"");
    tmp=xstrcat(tmp,from);
    tmp=xstrcat(tmp,"\"");
/*printf("DBG: tmp=%s\n",tmp);
*/

		swap_uid_gid();
    resp_fp=popen(tmp,"w");
		swap_uid_gid();

    if(resp_fp==NULL)
    {
      /* TODO: maybe process query with resp_fp == NULL */
      e_printf("unable to popen(%s)",tmp);
      return;
    }
  }

	fprintf(resp_fp,"Subject: gtic response\n\n");

  l_printf("area_manager: processing %s (%s)",ftn,from);

  if(resp_fp)
    fprintf(resp_fp,"gtic response for \"%s\" (%s)\n\n",from,ftn);

  user=list_find_entry(users,ftn);
  if(user==NULL)
  {
    if(resp_fp)
      fprintf(resp_fp,"sorry, you absent in our users list\n");
    l_printf("link absent in users_file");
  }
  else if(!strcmp(user->passwd,"*"))
  {
    if(resp_fp)
      fprintf(resp_fp,"sorry, but you rejected from area manager\n");
    l_printf("link has \"*\" password - rejected");
  }
  else if(strcasecmp(user->passwd,subj))
  {
    if(resp_fp)
      fprintf(resp_fp,"sorry, your password is incorrect\n");
    l_printf("link give incorrect password");
  }
  else
  {
    if(resp_fp)
    {
      fprintf(resp_fp,"Your current status is: ");
      write_flag_tab_to_FILE(resp_fp,user->flags,
                            (struct flag_tab*)&user_flag_tab);
      fprintf(resp_fp,"\n\n");
    }
    while(1)
    {
      if(fgets(buff,sizeof(buff)-1,stdin)==NULL) break;
      delcrlf(buff);
			if(buff[0]==0) continue;

			if(strncmp(buff,"--",strlen("--"))==0) break; /* FIXME ? ;-) */
			
/*		skip Message-ID: and X-FTN-* and some ... FIXME (fixed ;-) 
			if(strncmp(buff,"Message-ID: ",strlen("Message-ID: "))==0) continue;
			if(strncmp(buff,"X-FTN-",strlen("X-FTN-"))==0) continue;
			if(strncmp(buff,"In-Reply-To:",strlen("In-Reply-To:"))==0) continue;
*/
      /* HELP */
      if(strcasecmp(buff,"%HELP")==0)
      {
        if(resp_fp) fprintf(resp_fp,"> %%HELP\n");
				if(help_file==NULL)
				{
          l_printf("%%HELP - help_file not defined in config");
				  if(resp_fp)
						fprintf(resp_fp,"sorry, help file not available on server\n");
				}
				else
				{
				  l_printf("%%HELP");
					if(resp_fp)
					{
						help_fp=fopen(help_file,"rb");
						if(help_fp==NULL)
						{
							l_printf("%%HELP - unable to open help_file");
							fprintf(resp_fp,"sorry, unable to open help file on server\n");
						}
						else
						{
							/* yes, we can use buff here */
							while(fgets(buff,sizeof(buff)-1,help_fp)!=NULL)
							{
								/* help_fp may contain text in DOS format, need to convert to
								 * UNIX format.
								 */ 
								delcrlf(buff);
								fprintf(resp_fp,"%s\n",buff);
							}
							fclose(help_fp);
						}
					}
				}
			}
      /* PAUSE */
      else if(strcasecmp(buff,"%PAUSE")==0)
      {
        l_printf("%%PAUSE");
				if(resp_fp) fprintf(resp_fp,"> %%PAUSE\nok\n");
				user->flags|=USER_PAUSE;
      }

      /* RESUME */
      else if(strcasecmp(buff,"%RESUME")==0)
      {
        l_printf("%%RESUME");
				if(resp_fp) fprintf(resp_fp,"> %%RESUME\nok\n");
				user->flags&=~USER_PAUSE;
      }

      /* PASSWD */
      else if(strncasecmp(buff,"%PASSWD",7)==0)
      {
        l_printf("%%PASSWD");
				if(resp_fp) fprintf(resp_fp,"> %%PASSWD\n");
				p=strschr(buff," \t");
				if(p)
				{
          if(user->passwd)
						xfree(user->passwd);
				  user->passwd=xstrcpy(p);
				  if(resp_fp)
						fprintf(resp_fp,"ok\n");
				}
				else
				{
				  l_printf("EMPTY %%PASSWD string");
				  if(resp_fp) fprintf(resp_fp,"failed, empty password not allowed\n");
				}
      }

      /* LINKED */
      else if(strcasecmp(buff,"%LINKED")==0)
      {
        l_printf("%%LINKED");
				if(resp_fp) fprintf(resp_fp,"> %%LINKED\n");
        if(resp_fp) fprintf(resp_fp,"%-20s %-6s %-10s %s\n",
					"AREA","WRITE","GROUP","DESCRIPTION");
        if(resp_fp) fprintf(resp_fp,"%-20s %-6s %-10s %s\n",
					"----","-----","-----","-----------");
				for(i=0;i<list_head_max(areas);i++)
				{
				  atmp=list_get_entry(areas,i);
				  ass(atmp!=NULL);
				  ltmp=atmp->users;
				  ass(ltmp!=NULL);
				  if(list_find(ltmp,ftn))
				  {
				    l_printf("[%s]",atmp->name);
				    if(resp_fp)
						{
							fprintf(resp_fp,"%-20s %-6s %-10s %s\n",
		    			atmp->name,"yes",atmp->group?atmp->group:"",
		    			atmp->desc?atmp->desc:"");
						}
				  }
				  else if(list_find(ltmp,ro_ftn))
				  {
				    l_printf("[%s]",atmp->name);
				    if(resp_fp)
						{
							fprintf(resp_fp,"%-20s %-6s %-10s %s\n",atmp->name,
		    			"",atmp->group?atmp->group:"",atmp->desc?atmp->desc:"");
						}
				  }
				}
      }
      
      /* LIST and UNLINKED */
      else if(strcasecmp(buff,"%LIST")==0 || strcasecmp(buff,"%UNLINKED")==0)
      {
        int fulllist,linked_mode;
				linked_mode=0; /* 0 - unlinked, 1 - readonly, 2 - readwrite */
				fulllist=strcasecmp(buff,"%LIST")?0:1;
        l_printf("%s",fulllist?"%LIST":"%UNLINKED");
				if(resp_fp) fprintf(resp_fp,"> %s\n",fulllist?"%LIST":"%UNLINKED");
        if(resp_fp) fprintf(resp_fp,"%-20s %-6s %-10s %s\n",
					"AREA","WRITE","GROUP","DESCRIPTION");
        if(resp_fp) fprintf(resp_fp,"%-20s %-6s %-10s %s\n",
					"----","-----","-----","-----------");
				for(i=0;i<list_head_max(areas);i++)
				{
				  atmp=list_get_entry(areas,i);
				  ass(atmp!=NULL);
				  ltmp=atmp->users;
				  ass(ltmp!=NULL);
				  linked_mode=list_find(ltmp,ro_ftn)?1:0;
				  if(linked_mode==0) linked_mode=list_find(ltmp,ftn)?2:0;
				  if(fulllist==0 && linked_mode!=0)
				    continue;
				  if(validate_group(atmp,user)==FALSE) continue;
	          l_printf("[%s]",atmp->name);
          if(resp_fp)
					{
						fprintf(resp_fp,"%-20s %-6s %-10s %s\n",
					  	atmp->name,linked_mode==2?"yes":linked_mode==1?"":
							atmp->flags&AREA_READONLY?"":"yes",atmp->group?atmp->group:"",
							atmp->desc?atmp->desc:"");
					}
				}
      }

      /* unlink from area */
      else if(buff[0]=='-')
      {
        l_printf("%s",buff);
				if(resp_fp) fprintf(resp_fp,"> %s\n",buff);
        atmp=list_find_entry(areas,buff+1);
				if(atmp==NULL)
				{
          l_printf("not found",buff);
				  if(resp_fp) fprintf(resp_fp,"area not found\n");
				  continue;
        }
				ltmp=atmp->users;
				ass(ltmp!=NULL);
				if(list_find(ltmp,ftn) || list_find(ltmp,ro_ftn))
				{
				  if(list_find(ltmp,ftn))
				    list_remove(ltmp,ftn);
				  else if(list_find(ltmp,ro_ftn))
				    list_remove(ltmp,ro_ftn);
				  if(resp_fp) fprintf(resp_fp,"unlinked\n");
				}
				else
				{
				  l_printf("don't connected");
				  if(resp_fp) fprintf(resp_fp,"you don't connected to this area\n");
				}
      }

      else
      /* link to area */
      {
        l_printf("%s",buff);
				if(resp_fp) fprintf(resp_fp,"> %s\n",buff);
        atmp=list_find_entry(areas,buff[0]=='+'?buff+1:buff);
				if(atmp==NULL)
				{
          l_printf("not found",buff);
				  if(resp_fp) fprintf(resp_fp,"area not found\n");
				  continue;
        }
				if(validate_group(atmp,user)==FALSE)
				{
          l_printf("invalid group",buff);
				  if(resp_fp) fprintf(resp_fp,"access violation\n");
				  continue;
				}
				ltmp=atmp->users;
				ass(ltmp!=NULL);
				if(list_find(ltmp,ftn) || list_find(ltmp,ro_ftn))
				{
          l_printf("already connected",buff);
				  if(resp_fp) fprintf(resp_fp,"already connected\n");
				  continue;
				}
				if(atmp->flags & AREA_READONLY)
				{
					/* link readonly */
					list_add(ltmp,ro_ftn,user);
					l_printf("(readonly)");
					if(resp_fp) fprintf(resp_fp,"connected in readonly mode\n");
				}
				else
				{
					/* link read-write */
					list_add(ltmp,ftn,user);
					l_printf("(read-write)");
					if(resp_fp) fprintf(resp_fp,"connected in read-write mode\n");
				}
      }
    }
  }

  if(resp_fp) pclose(resp_fp);
}


syntax highlighted by Code2HTML, v. 0.9.1