Logo Search packages:      
Sourcecode: dctc version File versions  Download package

display.c

/* DCTC - a Direct Connect text clone for Linux
 * Copyright (C) 2001 Eric Prevoteau
 *
 * display.c: Copyright (C) Eric Prevoteau <www@a2pb.gotdns.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
/*
$Id: display.c,v 1.3 2003/12/28 08:12:38 uid68112 Exp $
*/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <glib.h>

#include "display.h"

#include "var.h"

/* this mutex provides a lock for stdout to avoid display conflict between thread */
G_LOCK_DEFINE_STATIC(std_out);

static FILE *log_fd=NULL;
static FILE *errlog_fd=NULL;

/* this is the list of strings prefixed to displayed messaged */
/* always 5 bytes + a ] at the end. They must be in the same */
/* order as in DISP_MSG_TYPE */
static const char *msg_str_type[]={
                                                            "ERR  ]",
                              "DEBUG]",
                              "INFO ]",
                              "USER ]",
                              "OP   ]",
                              "USER+]",
                              "USER-]",
                              "CHAT ]",
                              "UINFO]",
                              "HUBNM]",
                              "SREST]",
                              "$USER]",
                              "$UL+ ]",
                              "$UL- ]",
                              "$UL# ]",
                              "$DL+ ]",
                              "$DL- ]",
                              "$DL# ]",
                              "HUB- ]",
                              "PRIV ]",
                              "XFERR]",
                              "XFERQ]",
                                                            "HUBGO]",
                              "$DL~ ]",
                                                            "CMDKB]",
                              "HUB+ ]",
                              "$LS+ ]",
                              "$LS- ]",
                              "$LS# ]",
                                                            "FLST ]",
                                                            "FLSTE]",
                              "$UL= ]",
                              "$DL= ]",
                              "$LS= ]",
                              "$LS~ ]",
                                                            "ASTRT]",
                                                            "ASTOP]",
                                                            "RFRSH]",
                                                            "BXFER]",
                                                            "VAR  ]",
                                                            "EXFER]",
                                                            "PASWD]",
                                                            "ADMIN]",
                              "$ULST]",
                                                            "PRGBR]",
                                                            "GQLSB]",
                                                            "GQLSC]",
                                                            "GQLSE]",
                                                            "GLSTB]",
                                                            "GLSTC]",
                                                            "GLSTE]",
                                                            "UALSB]",
                                                            "UALSC]",
                                                            "UALSE]",
                                                            "UALS+]",
                                                            "UALS-]",
                                                            "DRLAY]",         /* this message is never displayed, only the message content is */
                                                            "FLSTB]",
                                                            "LUSER]",
                                                            "LSCCH]",
                                                            "ULIST]",
                              };

#define ERR_TO_LOG(x)   if((errlog_fd!=NULL)&&(msg_type==ERR_MSG))      {x;}


/*******************************/
/* display a formatted message */
/**************************************************************************/
/* this function is thread safe, multiple disp_msg won't mix their output */
/* The displayed message will have this form:                             */
/* MSGTP] "fnc_name"xxxxx|yyyyy|                                          */
/* fnc_name can be NULL. one or more string can be provided. They will be */
/* append after the fnc_name and will be separated by |                   */
/**************************************************************************/
/* if produced_string is not NULL, the printed string is not freed but */
/* put inside.                                                         */
/***********************************************************************/
void disp_msg_full(DISP_MSG_TYPE msg_type,GString **produced_string,const char *fnc_name, ...)
{
      va_list ap;
      char *t;
      GString *o_str;
      int i;

      if(produced_string!=NULL)
            *produced_string=NULL;

      if((msg_type==DEBUG_MSG)&&(debug_mode==0))
            return;

      G_LOCK(std_out);
      o_str=g_string_new("");

      va_start(ap,fnc_name);

      if(msg_type==DISPLAY_RELAY)
      {
            t=va_arg(ap,char *);
            o_str=g_string_append(o_str,t);
            goto end_of_decode;
      }

      if(msg_str_type[msg_type]!=NULL)
      {
            g_string_sprintf(o_str,"%s",msg_str_type[msg_type]);
      }
      else
      {
            g_string_sprintf(o_str,"     ]");
      }

      if(fnc_name!=NULL)
      {
            g_string_sprintfa(o_str," \"%s\"",fnc_name);
      }
      else
      {
            g_string_sprintfa(o_str," \"\"");
      }

      t=va_arg(ap,char *);
      while(t!=NULL)
      {
            if(t[0]=='|')                 /* we can't use % like printf because it can appears (in nickname for instance). I use | */
            {
                  switch(t[1])
                  {
                        case 's':         g_string_sprintfa(o_str,"%s|",va_arg(ap,char *));
                                                      break;

                        case 'd':         g_string_sprintfa(o_str,"%d|",va_arg(ap,int));
                                                      break;
                        case 'u':         g_string_sprintfa(o_str,"%u|",va_arg(ap,unsigned int));
                                                      break;

                        case 'l':         switch(t[2])
                                                      {
                                                            case 'd':         g_string_sprintfa(o_str,"%ld|",va_arg(ap,long int));
                                                                                          break;
                                                            case 'u':         g_string_sprintfa(o_str,"%lu|",va_arg(ap,unsigned long int));
                                                                                          break;

                                                            default:    
                                                                                          /* never display an error message during a display, stdout is locked */
                                                                                          g_string_sprintfa(o_str,"unknown pattern: %s|",t);
                                                                                          break;
                                                      }
                                                      break;

                        default:                
                                                      g_string_sprintfa(o_str,"unknown pattern: %s|",t);
                                                      break;
                  }
            }
            else
            {
                  g_string_sprintfa(o_str,"%s|",t);
                  /* we can use | without problem because it is a reserved character in DC, it will never appears anywhere */
            }

            t=va_arg(ap,char *);
      }

      end_of_decode:
      g_string_sprintfa(o_str,"\n");
      /* now, o_str is the string to display */
      
      if(keyb_fd==0)                /* display the message if term exists */
            printf("%s",o_str->str);

      /* if log file exists, put it into */
      if(log_fd!=NULL)
            fprintf(log_fd,"%s",o_str->str);

      /* if err log file exists and it is an ERR] message, put it into */
      ERR_TO_LOG(fprintf(errlog_fd,"%s",o_str->str))

      G_LOCK(local_client_socket);
      if((local_client_socket!=NULL)&&(local_client_socket->len!=0))
      {
            /* send the message to all client currently connected */
            for(i=local_client_socket->len-1;i>=0;i--)
            {
                  int res;
                  int attempt=0;

                  /* the socket is by default in blocking mode. If a UI client disconnects during when a big set of messages */
                  /* are sent, DCTC may hang. This code makes 3 attempts before closing the UI client connection */
                  retry_send:
                  res=send(g_array_index(local_client_socket,int,i),o_str->str,o_str->len,MSG_DONTWAIT);
                  if((res==-1)&&(errno==EAGAIN))
                  {
                        attempt++;
                        if(attempt<3)
                        {
                              sleep(1);
                              goto retry_send;
                        }
                        else
                              goto faulty_connection;
                  }

                  if(res!=o_str->len)
                  {     /* on error, the client socket is closed and the socket is removed from the list */
                        int sck;

                        faulty_connection:
                        sck=g_array_index(local_client_socket,int,i);
                        shutdown(sck,2);
                        close(sck);
                        local_client_socket=g_array_remove_index_fast(local_client_socket,i);
                  }
            }
      }
      G_UNLOCK(local_client_socket);

      if(produced_string==NULL)
            g_string_free(o_str,TRUE);
      else
            (*produced_string)=o_str;

      if(log_fd!=NULL)
            fflush(log_fd);
      if(errlog_fd!=NULL)
            fflush(errlog_fd);

      va_end(ap);

      fflush(stdout);               /* flush stdout before unlocking */
      G_UNLOCK(std_out);
}

/****************************************************************************************/
/* same as the previous function except the string is not printed but written into file */
/****************************************************************************************/
void disp_msg_full_infile(int file_fd,DISP_MSG_TYPE msg_type,GString **produced_string,const char *fnc_name, ...)
{
      va_list ap;
      char *t;
      GString *o_str;

      if(produced_string!=NULL)
            *produced_string=NULL;

      if((msg_type==DEBUG_MSG)&&(debug_mode==0))
            return;

      o_str=g_string_new("");

      va_start(ap,fnc_name);

      if(msg_type==DISPLAY_RELAY)
      {
            t=va_arg(ap,char *);
            o_str=g_string_append(o_str,t);
            goto end_of_decode;
      }

      if(msg_str_type[msg_type]!=NULL)
      {
            g_string_sprintf(o_str,"%s",msg_str_type[msg_type]);
      }
      else
      {
            g_string_sprintf(o_str,"     ]");
      }

      if(fnc_name!=NULL)
      {
            g_string_sprintfa(o_str," \"%s\"",fnc_name);
      }
      else
      {
            g_string_sprintfa(o_str," \"\"");
      }

      t=va_arg(ap,char *);
      while(t!=NULL)
      {
            if(t[0]=='|')                 /* we can't use % like printf because it can appears (in nickname for instance). I use | */
            {
                  switch(t[1])
                  {
                        case 's':         g_string_sprintfa(o_str,"%s|",va_arg(ap,char *));
                                                      break;

                        case 'd':         g_string_sprintfa(o_str,"%d|",va_arg(ap,int));
                                                      break;
                        case 'u':         g_string_sprintfa(o_str,"%u|",va_arg(ap,unsigned int));
                                                      break;

                        case 'l':         switch(t[2])
                                                      {
                                                            case 'd':         g_string_sprintfa(o_str,"%ld|",va_arg(ap,long int));
                                                                                          break;
                                                            case 'u':         g_string_sprintfa(o_str,"%lu|",va_arg(ap,unsigned long int));
                                                                                          break;

                                                            default:    
                                                                                          /* never display an error message during a display, stdout is locked */
                                                                                          g_string_sprintfa(o_str,"unknown pattern: %s|",t);
                                                                                          break;
                                                      }
                                                      break;

                        default:                
                                                      g_string_sprintfa(o_str,"unknown pattern: %s|",t);
                                                      break;
                  }
            }
            else
            {
                  g_string_sprintfa(o_str,"%s|",t);
                  /* we can use | without problem because it is a reserved character in DC, it will never appears anywhere */
            }

            t=va_arg(ap,char *);
      }

      end_of_decode:
      g_string_sprintfa(o_str,"\n");
      /* now, o_str is the string to display */
      
      /* put the message in the file */
      write(file_fd,o_str->str,o_str->len);

      /* if log file exists, put it into */
      if(log_fd!=NULL)
            fprintf(log_fd,"%s",o_str->str);

      /* if err log file exists and it is an ERR] message, put it into */
      ERR_TO_LOG(fprintf(errlog_fd,"%s",o_str->str))

      if(produced_string==NULL)
            g_string_free(o_str,TRUE);
      else
            (*produced_string)=o_str;

      if(log_fd!=NULL)
            fflush(log_fd);
      if(errlog_fd!=NULL)
            fflush(errlog_fd);

      va_end(ap);
}

/***************************************************/
/* display a formatted message built from an array */
/***************************************************/
/* The displayed message will have this form:      */
/* MSGTP] "fnc_name"fix_part|yyyyy|                */
/* fnc_name can be NULL. yyyyy is the list of all  */
/* strings of string_array separated by '$'        */
/***************************************************/
void disp_msg_ptr_array(DISP_MSG_TYPE msg_type,const char *fnc_name,const char *fix_part,GPtrArray *string_array)
{
      GString *param;
      int i;

      param=g_string_new("");
      if((string_array!=NULL)&&(string_array->len>0))
      {
            g_string_assign(param,g_ptr_array_index(string_array,0));
            i=1;
            while(i<string_array->len)
            {
                  g_string_append_c(param,'$');
                  g_string_append(param,g_ptr_array_index(string_array,i));
                  i++;
            }
      }
      
      disp_msg_full(msg_type,NULL,fnc_name,fix_part,param->str,NULL);
      g_string_free(param,TRUE);
}

/***********************************/
/* change the current log filename */
/************************************************/
/* if filename==NULL, log into file is disabled */
/************************************************/
void change_logfile(char *filename)
{
      /* to avoid potential access conflict, we lock the display */
      G_LOCK(std_out);

      /* close the previously existing FILE */
      if(log_fd!=NULL)
      {
            fclose(log_fd);
            log_fd=NULL;
      }

      /* and open the new one if a filename is provided */
      if(filename!=NULL)
      {
            log_fd=fopen(filename,"ab");
            if(log_fd==NULL)
            {
                  disp_msg(ERR_MSG,"change_logfile",strerror(errno),NULL);
            }
      }
      G_UNLOCK(std_out);
}

/***************************************/
/* change the current ERR log filename */
/************************************************/
/* if filename==NULL, log into file is disabled */
/************************************************/
void change_errlogfile(char *filename)
{
      /* to avoid potential access conflict, we lock the display */
      G_LOCK(std_out);

      /* close the previously existing FILE */
      if(errlog_fd!=NULL)
      {
            fclose(errlog_fd);
            errlog_fd=NULL;
      }

      /* and open the new one if a filename is provided */
      if(filename!=NULL)
      {
            errlog_fd=fopen(filename,"ab");
            if(errlog_fd==NULL)
            {
                  disp_msg(ERR_MSG,"change_errlogfile",strerror(errno),NULL);
            }
      }
      G_UNLOCK(std_out);
}


Generated by  Doxygen 1.6.0   Back to index