diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/Defines.cs.in | 12 | ||||
-rwxr-xr-x | src/Makefile.am | 69 | ||||
-rwxr-xr-x | src/efax.cs | 605 | ||||
-rwxr-xr-x | src/evolution.cs | 134 | ||||
-rwxr-xr-x | src/fax.cs | 501 | ||||
-rwxr-xr-x | src/gfaxphonebook.cs | 498 | ||||
-rwxr-xr-x | src/gfaxprefs.cs | 302 | ||||
-rw-r--r-- | src/gfaxsend.cs | 364 | ||||
-rwxr-xr-x | src/gui.cs | 1137 | ||||
-rwxr-xr-x | src/guitools.cs | 540 | ||||
-rwxr-xr-x | src/hylafax.cs | 950 | ||||
-rw-r--r-- | src/main.cs | 243 | ||||
-rwxr-xr-x | src/newphonebook.cs | 187 | ||||
-rwxr-xr-x | src/phonebook.cs | 386 | ||||
-rwxr-xr-x | src/sendphonebook.cs | 242 |
15 files changed, 6170 insertions, 0 deletions
diff --git a/src/Defines.cs.in b/src/Defines.cs.in new file mode 100755 index 0000000..fab15cc --- /dev/null +++ b/src/Defines.cs.in @@ -0,0 +1,12 @@ + +using System; + +namespace gfax +{ + public class Defines + { + public static string VERSION = "@version@"; + public static string DATADIR = "@datadir@"; + public static string GNOME_LOCALE_DIR = DATADIR + "/locale"; + } +} diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100755 index 0000000..e71dd90 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,69 @@ +# 0169 - Don't warn about unused functions, they are called from libglade +# 0219 - Constructs like Gtk.TreeIter iter = new Gtk.TreeIter(); +CSC = mcs -nowarn:0169,0219 -debug + +TARGET = gfax.exe +WRAPPER = gfax +SCHEMA = $(top_srcdir)/gfax.schemas.in + +#CSFLAGS = -define:DEBUGEFAX +#CSFLAGS = -define:DEBUGHYLAFAX +#CSFLAGS = + +ASSEMBLIES = -r:Mono.Posix + +RESOURCES = \ + -resource:$(top_srcdir)/glade/gfax.glade,gfax.glade \ + -resource:$(top_srcdir)/glade/send-druid.glade,send-druid.glade \ + -resource:$(top_srcdir)/pixmaps/gfax.png,gfax.png \ + -resource:$(top_srcdir)/pixmaps/send.png,send.png + + +CSFILES = efax.cs \ + fax.cs \ + gui.cs \ + gfaxprefs.cs \ + gfaxsend.cs \ + gfaxphonebook.cs \ + newphonebook.cs \ + guitools.cs \ + hylafax.cs \ + main.cs \ + phonebook.cs \ + evolution.cs \ + sendphonebook.cs + + +GENERATED_CSFILES = Defines.cs Settings.cs + +Defines.cs: Defines.cs.in ../config.log + sed -e "s|\@version\@|$(VERSION)|" \ + -e "s|\@datadir\@|$(datadir)|" \ + -e "s|\@eprefix\@|$(eprefix)|" \ + < Defines.cs.in > Defines.cs + +Settings.cs: Settings.cs + env GCONF_CONFIG_SOURCE="" gconftool-2 --makefile-install-rule $(SCHEMA); \ + gconfsharp2-schemagen gfax $(SCHEMA) > $(srcdir)/Settings.cs + +gfax.exe: $(CSFILES) $(GENERATED_CSFILES) + $(CSC) $(CSFLAGS) $(GFAX_LIBS) $(ASSEMBLIES) $(RESOURCES) $(CSFILES) $(GENERATED_CSFILES) -o $@ + +all: gfax.exe + +install-data-local: $(TARGET) + $(mkinstalldirs) $(DESTDIR)$(pkglibdir) + $(INSTALL_PROGRAM) $(TARGET) $(DESTDIR)$(pkglibdir)/$(TARGET) + +uninstall-local: + rm -f $(DESTDIR)$(pkglibdir)/$(TARGET) + +EXTRA_DIST = \ + $(srcdir)/Defines.cs.in \ + $(CSFILES) + + +CLEANFILES = \ + gfax.exe \ + Defines.cs \ + Settings.cs diff --git a/src/efax.cs b/src/efax.cs new file mode 100755 index 0000000..d9df4dc --- /dev/null +++ b/src/efax.cs @@ -0,0 +1,605 @@ +// GFAX - Gnome fax application +// Copyright (C) 2003 - 2008 George A. Farris +// +// 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 3 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 Library 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. + + // Sequence to send a file is: + // 1) Make sure we're connected + // 2) Store the filename on the server [storefile_open] + // 3) Send the file line by line + // 4) Close the stream for sending the file + // 5) For all the phone numbers do: + // a) job_new [job_new] + // b) set all job parms [job_parm_set] + // c) submit the job [submit_job] + // 6) Close the connection. + +// Properties +// string Hostname, Username, Password +// int IPPort + +//#define DEBUGEFAX + +namespace gfax { + using Gtk; + using Mono.Unix; + using System; + using System.IO; + using System.Text; //Encoding.ASCII.GetBytes + using System.Collections; + using System.Net; + using System.Threading; + using System.Net.Sockets; + using System.Diagnostics; + + + public class Efax + { + private static System.Threading.Thread thread; + string user; + + + //Speaker Volume + string[] speakerVolume = {"L0","L1","L2","L3"}; + const int VERY_LOW = 0; + const int LOW = 1; + const int MEDIUM = 2; + const int HIGH = 3; + + // Speaker modes + string[] speakerMode = {"M0","M1","M2","M3"}; + const int NEVER = 0; + const int UNTIL_CARRIER = 1; + const int ALWAYS_ON = 2; + const int ON_RECEIVE_ONLY = 3; + + string[] modemType = {@"-j\Q4",@"-j\Q1",@"-j*F1",@"-j&H2&I0&R1&D3I4",@"-or"}; + + + /* + # FCINIT='-j\Q4' # AT&T (Dataport, Paradyne) + # FCINIT='-j\Q1' # Motorola (Power Modem, 3400 Pro,...) + # FCINIT='-j*F1' # QuickComm (Spirit II) + # FCINIT='-j&H2&I0&R1&D3I4' # USR (Courier, Sportster) + # FCINIT='-or' # Multi-Tech (for bit reversal) + */ + + // Don't need this anymore + //TextWriter statusfile = null; + + public Efax () + { + + // Set initial modem settings, gconfsharp-schemagen doesn't like "&" + // so can't set a default in gfax.schemas + if ( Settings.EfaxModemInit == "" ) + Settings.EfaxModemInit = "-iZ -i&FE0&D2S7=120 -i&C0"; + if ( Settings.EfaxModemFcinit == "" ) + Settings.EfaxModemFcinit = "-j&H2&I0&R1&D3I4"; + if ( Settings.EfaxModemReset == "" ) + Settings.EfaxModemReset = "-kZ"; + + //Don't need this anymore + //statusfile = TextWriter.Synchronized(File.CreateText(gfax.Procfile)); + } + + public void close () + { + } + + // Method status(queue) + // + // queue is the queue fax system it can be one of: + // 'sendq', 'doneq' or 'recvq' + // + // Return a string containing lines formatted like so + // "jobid=number=status=owner=pages=dials=error=sendat\n" + // such as: + // "2=5551212=S=george=2=1=error message=2004/03/09 18.01.51\n" + public string status (string queue) + { + StreamReader infile = null; + string[] sts = new string[11]; + string path; + string buf; + + + if (queue == "sendq") + path = gfax.SpoolDirectory; + else if (queue == "doneq") + path = gfax.SpoolDirectory + "/doneq"; + else + path = gfax.SpoolDirectory + "/recq"; + + string[] control_files = Directory.GetFiles(path, "C_*"); + string[] lines = new string[control_files.Length]; + int num_lines = 0; + + foreach (string s in control_files) { + try { + infile = File.OpenText(s); + + for (int i=0; (buf = infile.ReadLine()) != null; i++) { + string[] sa = buf.Split('='); + if ( sa[1].Length != 0 ) + sts[i] = sa[1]; + else + sts[i] = "-"; + } + infile.Close(); + // Purge doneq files if older than 5 days. + if ( queue == "doneq" ) + if ( (DateTime.Now).Subtract(File.GetCreationTime(s)).Days > 5 ) + File.Delete(s); + + lines[num_lines++] = String.Format("{0}={1}={2}={3}={4}={5}={6}={7}\n", + sts[0],sts[2],sts[3],sts[4],sts[5],sts[6],sts[10],sts[7]); + } + catch (Exception e) { + //return; + } + } + + return String.Concat(lines); + } + + // send_init (string filename) + // + // Here we should convert the file with ghostscript and return a directory + // that points to the converted files to send, one per page. There should + // be some status messages passed to the user to let them know whats going on. + // Maybe a dialog box. + // + // We also setup the status message system. + public string send_init (string fname) + { + StreamReader fp = null; + double lines = 0; + string resolution = "204x98"; // normal res + + // Get new directory name and make it + Random rand = new Random(); + string rand_file = rand.Next().ToString(); + string dir_name = String.Format("{0}/D_{1}",gfax.SpoolDirectory, rand_file); + // TODO proper checks here, this is nasty + Directory.CreateDirectory(dir_name); + + + // get the fax options + if (gfax.sendWizardResolution) { + resolution = "204x196"; + }else { + if (Settings.HiResolution) + resolution = "204x196"; + } + + string papersize = Settings.EfaxPapersize; + + + //figure out how many lines in the file for progress bar + // TODO progress bar and error + try { fp = File.OpenText(fname); } + catch (Exception e) { } + + while ( (fp.ReadLine()) != null ) { + lines = lines + 1; + } + fp.Close(); + + + try { fp = File.OpenText(fname); } + catch (Exception e) { } + + if (Settings.Faxtracing == true) { + Console.WriteLine("[Efax.send_init] File :{0} is open and has {1} lines", fname,lines); + } + + fp.Close(); + + + // TODO need random temp file name + if (Settings.Faxtracing == true) { + Console.WriteLine("[Efax.send_init] Converting file with gs"); + Console.WriteLine(" Filename -> {0}",fname); + Console.WriteLine(" Resolution -> {0}",resolution); + Console.WriteLine(" Directory -> {0}",dir_name); + Console.WriteLine(" Papersize -> {0}\n",papersize); + } + + ProcessStartInfo pidInfo = new ProcessStartInfo(); + pidInfo.FileName = "gs"; + + pidInfo.Arguments = String.Concat( + "-q -sDEVICE=tiffg3 -r", + resolution, + " -dNOPAUSE -dSAFER -dBATCH", + " -sOutputFile=", + dir_name, + "/tmp.%03d -sPAPERSIZE=", + papersize, " ",fname); + + if (Settings.Faxtracing == true) { + Console.WriteLine("[Efax.send_init]\n {0}", pidInfo.Arguments); + } + + Process pid = Process.Start(pidInfo); + pid.WaitForExit(); + + return dir_name; + } + + // Method send(string directory, contact) + // + // Sequence to send a file is: + public void send (string directory, GfaxContact contact) + { + StreamWriter outfile; + int pages; + + + string emailAddress = Settings.EmailAddress; + string emailNotify = "none"; + + // Get advanced options + if (gfax.fromSendWizard) { + if (gfax.sendWizardEmailNotify) { + emailNotify = "done"; + emailAddress = gfax.sendWizardEmailAddress; + } + } else { + if (Settings.EmailNotify) + emailNotify = "done"; + } + + //2004/03/09 18.01.51 + // Format time to send + DateTime st = DateTime.Now; + string tts = String.Format("{0}/{1:00}/{2:00} {3:00}.{4:00}.00", + st.Year, st.Month, st.Day, st.Hour, st.Minute); + + // get next jobid + if ( Settings.EfaxNextJobid > 998 ) + Settings.EfaxNextJobid = 1; + else + Settings.EfaxNextJobid++; + + // open directory and count files, that will be the number of pages. + pages = Directory.GetFiles(directory).Length; + + // build filename + Random rand = new Random(); + string rand_file = rand.Next().ToString(); + string tfname = String.Format("{0}/C_{1}.{2}",gfax.SpoolDirectory, contact.PhoneNumber, rand_file); + + // TODO error stuff + //Open new status file + try { outfile = File.CreateText(tfname); } + catch (Exception e) { return; } + outfile.Write("Jobid="); + outfile.WriteLine(Settings.EfaxNextJobid); + outfile.Write("JobDirectory="); + outfile.WriteLine(directory); + outfile.Write("PhoneNumber="); + outfile.WriteLine(contact.PhoneNumber); + outfile.Write("Status="); + outfile.WriteLine("P"); + outfile.Write("Owner="); + outfile.WriteLine(Environment.GetEnvironmentVariable("USERNAME")); + outfile.Write("Pages="); + outfile.WriteLine(pages.ToString()); + outfile.Write("Dials="); + outfile.WriteLine(0); + outfile.Write("Sendat="); + outfile.WriteLine(tts); + outfile.Write("Notification="); + outfile.WriteLine(emailNotify); + outfile.Write("Email="); + outfile.WriteLine(emailAddress); + outfile.Write("ErrorMessage="); + outfile.WriteLine(""); + outfile.Close(); + + // jobid might need to be Convert.ToInt32 + + } + + public void job_delete (string jobid) + { + StreamReader infile = null; + string[] sts = new string[11]; + string buf; + + string[] controlFiles = Directory.GetFiles(gfax.SpoolDirectory, "C_*"); + + foreach (string controlFile in controlFiles) { + try { + infile = File.OpenText(controlFile); + + for (int i=0; (buf = infile.ReadLine()) != null; i++) { + string[] sa = buf.Split('='); + if ( sa[1].Length != 0 ) + sts[i] = sa[1]; + else + sts[i] = "-"; + } + infile.Close(); + + if ( sts[0] == jobid ) { + File.Delete(controlFile); + Directory.Delete(sts[1], true); + break; + } + } + catch (Exception e) {continue; } + } + + // end up here with control file name + return; + } + + public string job_kill (string jobid) + { + return null; + } + + public void run_efaxd () + { + // Create the thread object, passing in the efaxd method + WaitCallback callback = new WaitCallback(efaxd); + ThreadPool.QueueUserWorkItem(callback); + } + + /* efaxd + * For now just cycle through the control files and send the fax + * + */ + private void efaxd (object state) + { + thread = System.Threading.Thread.CurrentThread; + + StreamReader infile = null; + string[] sts = new string[11]; + string buf; + //bool fatalError = false; + int retries; + string speakerModeVolume; + + //string jobid, number, status, owner, pages, dials, error, sendat; + System.Threading.Thread.Sleep(15000); // Don't start immediately + + while (true) { + Application.Invoke (delegate {gfax.GAppbar.ClearStack();}); + Application.Invoke (delegate {gfax.GAppbar.Push(Catalog.GetString("Scanning control files."));}); + + // while there are job files in the folder + while (Directory.GetFiles(gfax.SpoolDirectory, "C_*").Length > 0) { + + string[] controlFiles = Directory.GetFiles(gfax.SpoolDirectory, "C_*"); + // for each job try send it + foreach (string controlFile in controlFiles) { + if (Settings.Faxtracing == true) { + Console.WriteLine("Control files are ----> {0}", controlFile); + } + + //Application.Invoke (delegate {gfax.GAppbar.ClearStack();}); + Application.Invoke (delegate {gfax.GStatusTextBuffer.InsertAtCursor( + Catalog.GetString("Running job " + controlFile));}); + + try { + infile = File.OpenText(controlFile); + + for (int i=0; (buf = infile.ReadLine()) != null; i++) { + string[] sa = buf.Split('='); + if ( sa[1].Length != 0 ) + sts[i] = sa[1]; + else + sts[i] = "-"; + } + infile.Close(); + if (Settings.Faxtracing == true) { + Console.WriteLine("[Efaxd] Buffer is {0}", buf); + } + } + catch (Exception e) {continue; } + + //lines[num_lines++] = String.Format("{0}={1}={2}={3}={4}={5}={6}={7}\n", + // sts[0],sts[2],sts[3],sts[4],sts[5],sts[6],sts[10],sts[7]); + + // If we aborted for some reason check the retries + if (Convert.ToInt32(sts[6]) >= Settings.EfaxRetries) { + sts[10] = Catalog.GetString("Busy retries exceeded"); + update_status_code(sts, controlFile, "F"); + continue; + } + + sts[10] = ""; // clear error message + update_status_code(sts, controlFile, "R"); + + // default "-iM1L0" + speakerModeVolume = String.Concat("-i", + speakerMode[Settings.EfaxModemSpeakerMode], + speakerVolume[Settings.EfaxModemSpeakerVolume]); + + string [] tifFiles = Directory.GetFiles(sts[1], "tmp.*"); + StringBuilder filesToSend = new StringBuilder(); + foreach (string f in tifFiles) { + filesToSend.Append(f); + filesToSend.Append(" "); + } + + + ProcessStartInfo pidInfo = new ProcessStartInfo(); + pidInfo.FileName = "efax"; + pidInfo.RedirectStandardError = true; + pidInfo.UseShellExecute = false; + //used for testing + //Thread.Sleep(5000); + //pidInfo.FileName = "echo"; + //pidInfo.FileName = "sleep 5"; + + pidInfo.Arguments = String.Concat( + "-d /dev/", Settings.EfaxModemDevice, //modem port + " -x ", Settings.EfaxLockfile, Settings.EfaxModemDevice, // lockfile + " \"", Settings.EfaxModemInit, "\"", // init sequence + " \"", speakerModeVolume, "\"", // speaker enable / mode + " -l \"", Settings.FaxNumber, "\"", // Our fax number + " \"", Settings.EfaxModemReset, "\"", // how to reset modem + " -f /usr/bin/efaxfont", + " -h \'%d/%d\'", // should be name number and date + " -v i", // session progress information + " -t T", sts[2], // should make sure there are no bad chars + " ", filesToSend); // files to send + + if (Settings.Faxtracing == true) { + Console.WriteLine("[Efax.send]\n {0}", pidInfo.Arguments); + } + Application.Invoke (delegate {gfax.GAppbar.ClearStack();}); + Application.Invoke (delegate {gfax.GAppbar.Push(Catalog.GetString("Sending facsimile..."));}); + Process pid = Process.Start(pidInfo); + StreamReader myStreamReader = pid.StandardError; + + //start the pulser + Application.Invoke (delegate {gfax.Pulser.StartPulse();}); + Application.Invoke (delegate {gfax.Status.Append("");}); + + while (!pid.HasExited) { + string str = myStreamReader.ReadLine(); + Application.Invoke (delegate {gfax.Status.Append(str);}); + System.Threading.Thread.Sleep(200); + } + //stop the pulser. + Application.Invoke (delegate {gfax.Pulser.EndPulse();}); + + if (Settings.Faxtracing == true) { + Console.WriteLine("[Efax.efaxd] Exit code - {0}", pid.ExitCode); + } + + switch (pid.ExitCode) { + case 0: + // If successful then mv the control file to the done queue and flag + // a date for it's removal. + sts[10] = Catalog.GetString("Success"); + update_status_code(sts, controlFile, "D"); + // remove directory path + string basefilename = controlFile.Remove(0, gfax.SpoolDirectory.Length + 1); + string newfilename = String.Concat(gfax.SpoolDirectory,"/doneq/", basefilename); + File.Move(controlFile, newfilename); + break; + case 1: + // busy number, continue after timeout + // update listview as well + retries = Convert.ToInt32(sts[6]); + if (retries++ < Settings.EfaxRetries) { + sts[6] = retries.ToString(); + update_status_code(sts, controlFile, "W"); + } + else { + sts[10] = Catalog.GetString("Busy retries exceeded"); + update_status_code(sts, controlFile, "F"); + } + break; + case 2: + // fatal errors - no retry + //fatalError = true; + // change code in file + sts[10] = Catalog.GetString("Fatal error"); + update_status_code(sts, controlFile, "F"); + break; + case 3: + // Modem error - no retry + //fatalError = true; + sts[10] = Catalog.GetString("Fatal modem error"); + update_status_code(sts, controlFile, "F"); + break; + case 4: + // Modem not responding + //fatalError = true; + sts[10] = Catalog.GetString("Modem not responding"); + update_status_code(sts, controlFile, "B"); + break; + case 5: + // Program terminated + //fatalError = true; + sts[10] = Catalog.GetString("Program terminated"); + update_status_code(sts, controlFile, "F"); + break; + }// end of switch + + //sleep between each fax for the modem to stablize + System.Threading.Thread.Sleep(3000); + } // end of foreach + // This basically sleeps between busy numbers. + System.Threading.Thread.Sleep(30000); + } + System.Threading.Thread.Sleep(30000); // sleep 30 seconds + // Moved this from case 0 above + if (Settings.Faxtracing == true) { + Console.WriteLine("Deleting --->{0}", sts[1]); + } + //Directory.Delete(sts[1], true); + }// end of while + } + + + // Updates the status code in the control file and writes it back to disk + public void update_status_code (string[] job, string file, string status) + { + string fname = file; + + if ( status == "F" ) { + string filename = file.Remove(0, gfax.SpoolDirectory.Length + 1); + fname = String.Concat(gfax.SpoolDirectory,"/doneq/", filename); + File.Delete(file); + Directory.Delete(job[1], true); + } + + + // Thread safe + TextWriter outfile = TextWriter.Synchronized(File.CreateText(fname)); + + // TODO change this to string.concat and just issue one write + try { + //outfile = File.CreateText(file); + + outfile.Write("Jobid="); + outfile.WriteLine(job[0]); + outfile.Write("JobDirectory="); + outfile.WriteLine(job[1]); + outfile.Write("PhoneNumber="); + outfile.WriteLine(job[2]); + outfile.Write("Status="); + outfile.WriteLine(status); + outfile.Write("Owner="); + outfile.WriteLine(job[4]); + outfile.Write("Pages="); + outfile.WriteLine(job[5]); + outfile.Write("Dials="); + outfile.WriteLine(job[6]); + outfile.Write("Sendat="); + outfile.WriteLine(job[7]); + outfile.Write("Notification="); + outfile.WriteLine(job[8]); + outfile.Write("Email="); + outfile.WriteLine(job[9]); + outfile.Write("ErrorMessage="); + outfile.WriteLine(job[10]); + + outfile.Close(); + } + catch (Exception e) {} + } + + } +} diff --git a/src/evolution.cs b/src/evolution.cs new file mode 100755 index 0000000..5622a69 --- /dev/null +++ b/src/evolution.cs @@ -0,0 +1,134 @@ +// GFAX - Gnome fax application +// Copyright (C) 2003 - 2008 George A. Farris +// +// 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 3 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 Library 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. + +namespace gfax { + using System; + using System.IO; + using GLib; + using Gtk; + using GtkSharp; + using System.Collections; + using System.Reflection; + using Evolution; + + //************************************************************************ + // + // + // + public class EdsPhoneBooks + { + + private void OnContactsAdded (object o, Evolution.ContactsAddedArgs args) + { + Console.WriteLine ("Contacts added:"); + foreach (Evolution.Contact contact in args.Contacts) { + Console.WriteLine ("\nId: {0}", contact.Id); + Console.WriteLine ("Fullname: {0}", contact.FullName); + } + } + + private void OnContactsChanged (object o, Evolution.ContactsChangedArgs args) + { + } + + private void OnContactsRemoved (object o, Evolution.ContactsRemovedArgs args) + { + + } + + public ArrayList GetPhoneBooks () + { + ArrayList ebooks = new ArrayList(); + + SourceList slist = new SourceList ("/apps/evolution/addressbook/sources"); + if (slist != null) { + SList group_list = slist.Groups; + //Console.WriteLine ("Group count: {0}", group_list.Count); + + foreach (SourceGroup group in group_list) { + //Only get phone books on this machine. + if (group.Name == "On This Computer") { + SList src_list = group.Sources; + + foreach (Evolution.Source src in src_list) { + ebooks.Add(src.Name); + } + } + } + } + return ebooks; + } + + + public ArrayList GetContacts (string bookName) + { + string contact_fax = null; + ArrayList ebooks = new ArrayList(); + ArrayList records = new ArrayList(); + + SourceList slist = new SourceList ("/apps/evolution/addressbook/sources"); + if (slist != null) { + SList group_list = slist.Groups; + foreach (SourceGroup group in group_list) { + //Only get phone books on this machine. + if (group.Name == "On This Computer") { + SList src_list = group.Sources; + + foreach (Evolution.Source src in src_list) { + if (src.Name == bookName) { + //Book bk = Book.NewSystemAddressbook (); + Book bk = new Book(src); + bk.Open (true); + + BookQuery q = BookQuery.AnyFieldContains (""); + Contact[] contactlist = bk.GetContacts (q); + //Console.WriteLine ("Contact count (range) : {0}", contactlist.Length); + + if (contactlist != null) { + + foreach (Contact comp in contactlist) { + contact_fax = null; + + if (comp.BusinessFax != null && comp.BusinessFax != String.Empty) { + contact_fax = comp.BusinessFax; + } + else if (comp.OtherFax != null && comp.OtherFax != String.Empty) { + contact_fax = comp.OtherFax; + } + else if (comp.HomeFax != null && comp.HomeFax != String.Empty) { + contact_fax = comp.HomeFax; + } + + if (contact_fax != null) { + GfaxContact gc = new GfaxContact(); + //Console.WriteLine ("Id: {0}", comp.Id); + gc.PhoneNumber = contact_fax; + gc.ContactPerson = comp.FullName; + gc.Organization = comp.Org; + records.Add(gc); + } + } + } + } + } + } + } + } + return records; + } + } +} diff --git a/src/fax.cs b/src/fax.cs new file mode 100755 index 0000000..91d0f0f --- /dev/null +++ b/src/fax.cs @@ -0,0 +1,501 @@ +// GFAX - Gnome fax application +// Copyright (C) 2003 - 2008 George A. Farris +// +// 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 3 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 Library 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. + +//#define DEBUGHYLAFAX + + +namespace gfax { + using Mono.Unix; + using System; + using System.Collections; + + public enum FaxStatus: int { + Sent, + Fail, + New, + Busy, + Block, + Sleep, + Run, + Receiving, + Received + }; + + public class Fax + { + static Hylafax hfax; + static Efax efax; + static bool firstRun = true; + + public class FaxQueue + { + public string Jobid; + public string Number; + public string Status; + public FaxStatus StatusType; + public string Owner; + public string Pages; + public string Dials; + public string Error; + public object Sendat; + } + + public class FaxRecQueue + { + public string Pages; + public string Status; + public FaxStatus StatusType; + public string Sender; + public object TimeReceived; + public string Filename; + } + + public static string async_get_server_status () + { + + if (Settings.TransmitAgent == "hylafax") { + hfax = new Hylafax(); + + if ( !hfax.connect() ) + return (Catalog.GetString("No Connection")); + hfax.asyncstatus("status"); + hfax.close(); + hfax = null; + return (""); + } + + if (Settings.TransmitAgent == "efax") { + //TODO put modem ready status here + if (firstRun) { + firstRun = false; + return (Catalog.GetString("Efax transmit process running...\nScanning job files every 30 seconds.")); + } + else + return (null); + } + + return (Catalog.GetString("Error transport agent not specified!")); + } + + public static ArrayList async_get_queue_status (string queue) + { + if (Settings.TransmitAgent == "hylafax") { + hfax = new Hylafax(); + + if ( hfax.connect() ) + hfax.asyncstatus(queue); + hfax.close(); + hfax = null; + } + + if (Settings.TransmitAgent == "efax") { + string reply = gfax.efax.status(queue); + + if (queue == "doneq" || queue == "sendq") + return (parse_senddone(reply)); + else // (queue == "recvq") + return (parse_receive(reply)); + } + return (null); + } + + // parse the send or done queue + public static ArrayList parse_senddone (string reply) + { + ArrayList list = new ArrayList(); + + if (reply.Length > 0) { + foreach (string s in reply.Split('\n')) { + FaxQueue hq = new FaxQueue(); + //Console.WriteLine("s length equals --> {0}", s.Length); + if (s.Length == 0 ) + break; + + string[] sa = s.Split('='); + + // TODO put error here about bad network comms + if (sa.Length != 8) { + break; + } + + if ( sa[0].Length != 0 ) + hq.Jobid = sa[0].Trim(); + else + hq.Jobid = ""; + if ( sa[1].Length != 0 ) + hq.Number = sa[1].Trim(); + else + hq.Number = ""; + if ( sa[2].Length != 0 ) { + switch (sa[2]) { + case "R": + hq.Status = Catalog.GetString("Run"); + hq.StatusType = FaxStatus.Run; + break; + case "S": + hq.Status = Catalog.GetString("Sleep"); + hq.StatusType = FaxStatus.Sleep; + break; + case "B": + hq.Status = Catalog.GetString("Block"); + hq.StatusType = FaxStatus.Block; + break; + case "W": + hq.Status = Catalog.GetString("Busy"); + hq.StatusType = FaxStatus.Busy; + break; + case "D": + hq.Status = Catalog.GetString("Done"); + hq.StatusType = FaxStatus.Sent; + break; + case "F": + hq.Status = Catalog.GetString("Fail"); + hq.StatusType = FaxStatus.Fail; + break; + case "P": + hq.Status = Catalog.GetString("New"); + hq.StatusType = FaxStatus.New; + break; + } + } + else + hq.Status = ""; + if ( sa[3].Length != 0 ) + hq.Owner = sa[3].Trim(); + else + hq.Owner = ""; + if ( sa[4].Length != 0 ) + hq.Pages = sa[4].Trim(); + else + hq.Pages = ""; + if ( sa[5].Length != 0 ) + hq.Dials = sa[5].Trim(); + else + hq.Dials = ""; + if ( sa[6].Length != 0 ) + hq.Error = sa[6]; + else + hq.Error = ""; + + if ( sa[7].Length != 0 ) { // 2004/03/09 18.01.51 + try { + hq.Sendat = (DateTime)System.DateTime.ParseExact(sa[7].Replace(".", ":").Trim(), "yyyy/MM/dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture); + } + catch(FormatException e) + { + hq.Sendat = null; + } + } else { + hq.Sendat = null; + } + + list.Add(hq); + } + + } else { // no status + + FaxQueue hq = new FaxQueue(); + hq.Jobid = ""; + hq.Number = ""; + hq.Status = ""; + hq.Owner = ""; + hq.Pages = ""; + hq.Dials = ""; + hq.Error = ""; + hq.Sendat = null; + + list.Add(hq); + } + + return (list); + } + + // parse the receive queue + // + //Page S Sender/TSI Recvd@ Filename + //1 +49 30 7865224 10Nov04 fax00004.tif + // should come back as + //1= =+49 30 7865224=10Nov04=fax00004.tif + public static ArrayList parse_receive (string reply) + { + ArrayList list = new ArrayList(); + + + if (reply.Length > 0) { + foreach (string s in reply.Split('\n')) { + FaxRecQueue hq = new FaxRecQueue(); + if (s.Length == 0 ) + break; + + string[] sa = s.Split('='); + if (sa.Length != 5) { + break; + } + + if ( sa[0].Length != 0 ) + hq.Pages = sa[0].Trim(); + else + hq.Pages = ""; + if ( sa[1].Length != 0 ) + switch (sa[1]) { + case "N*": + hq.Status = Catalog.GetString("Receiving"); + hq.StatusType = FaxStatus.Receiving; + break; + case "N ": + hq.Status = Catalog.GetString("Done"); + hq.StatusType = FaxStatus.Received; + break; + } + if ( sa[2].Length != 0 ) + hq.Sender = sa[2].Trim(); + else + hq.Sender = ""; + if ( sa[3].Length != 0 ) + { + try { + hq.TimeReceived = (DateTime)System.DateTime.ParseExact(sa[3], "ddMMMyy", System.Globalization.CultureInfo.InvariantCulture); + } + catch(FormatException e ) + { + hq.TimeReceived = null; + } + } + else + hq.TimeReceived = null; + if ( sa[4].Length != 0 ) + hq.Filename = sa[4].Trim(); + else + hq.Filename = ""; + + list.Add(hq); + } + + } else { // no status + + FaxRecQueue hq = new FaxRecQueue(); + hq.Pages = ""; + hq.Status = ""; + hq.Sender = ""; + hq.TimeReceived = null; + hq.Filename = ""; + + list.Add(hq); + } + + return (list); + } + + + + public static void sendfax (string fname) + { + string remote_fname; + + if (Settings.Faxtracing == true) { + Console.WriteLine("[Fax.sendfax] File name is : {0}", fname); + } + + if (Settings.TransmitAgent == "hylafax") { + Hylafax hfaxsf = new Hylafax(); + // hylafax actually stores the file to the server + hfaxsf.connect(); + remote_fname = hfaxsf.send_init(fname); + + // if "Cancel" button pressed on progess bar + if (remote_fname == "cancelled") + return; + + if (Settings.Faxtracing == true) { + if (Settings.TransmitAgent == "hylafax") { + Console.WriteLine("[Fax.sendfax] Remote file name is : {0}", remote_fname); + } + } + + //System.Threading.Thread.Sleep(2000); + + IEnumerator enu = gfax.Destinations.GetEnumerator(); + + if (Settings.Faxtracing == true) { + if (Settings.TransmitAgent == "hylafax") { + Console.WriteLine("[Fax.sendfax] Destinations has a count of : {0}", gfax.Destinations.Count); + } + } + + while ( enu.MoveNext() ) { + // TODO try catch exception here + GfaxContact c = (GfaxContact)enu.Current; + + if (Settings.Faxtracing == true) { + if (Settings.TransmitAgent == "hylafax") { + Console.WriteLine("[Fax.sendfax] In while loop contact is -----> {0}", c.PhoneNumber); + } + } + + hfaxsf.send(remote_fname, c); + + if (Settings.Faxtracing == true) { + if (Settings.TransmitAgent == "hylafax") { + Console.WriteLine("[Fax.sendfax] In while loop bottom... "); + } + } + + //System.Threading.Thread.Sleep(1000); + // open the log and log out going fax to server + // Date Time PhoneNumber Organization ContactPerson + // log file is in ~/.etc/gfax + //if (Settings.LogEnabled) + //log_it((GfaxContact)enu.Current); + } + + if (Settings.Faxtracing == true) { + if (Settings.TransmitAgent == "hylafax") { + Console.WriteLine("[Fax.sendfax] End of send contact loop..."); + } + } + + hfaxsf = null; + } + + + //Efax transport + if (Settings.TransmitAgent == "efax") { + + // Convert the file with ghostscript + string directory = gfax.efax.send_init(fname); + if (directory == "cancelled") + return; + + IEnumerator enu = gfax.Destinations.GetEnumerator(); + while ( enu.MoveNext() ) { + gfax.efax.send(directory, (GfaxContact)enu.Current); + if (Settings.LogEnabled) + log_it((GfaxContact)enu.Current); + } + } + } + + public static bool recvfax (string fname) + { + + // Hylafax support + if (Settings.TransmitAgent == "hylafax") { + hfax = new Hylafax(); + // hylafax actually stores the file to the server + hfax.connect(); + return(hfax.getfile(fname)); + } + + // Efax transport + if (Settings.TransmitAgent == "efax") { + return false; + } + + return false; + } + + + public static void log_it (GfaxContact contact) + { + + } + + + public static void modify_job (string jobid, string number, string sendat, string dials) + { + if (Settings.TransmitAgent == "hylafax") { + hfax = new Hylafax(); + hfax.connect(); + hfax.job_select(jobid); + hfax.job_suspend(); + hfax.job_param_set("SENDTIME", sendat); + hfax.job_param_set("EXTERNAL", number); + hfax.job_param_set("DIALSTRING", number); + hfax.job_param_set("MAXDIALS", dials); + hfax.job_submit(); + hfax = null; + } + + /* + if (Settings.TransmitAgent == "efax") { + gfax.efax.job_kill(jobid); + gfax.efax.job_delete(jobid); + } + */ + + } + + public static void resubmit_job (string jobid, string number, string sendat, string dials) + { + // will have to query the job, get the file name + // possibly retrieve the file and then re-submit the job + + if (Settings.TransmitAgent == "hylafax") { + hfax = new Hylafax(); + hfax.connect(); + hfax.job_select(jobid); + + /* + hfax.job_reset("P"); + hfax.job_suspend(); + hfax.job_param_set("SENDTIME", sendat); + hfax.job_param_set("EXTERNAL", number); + hfax.job_param_set("DIALSTRING", number); + hfax.job_param_set("MAXDIALS", dials); + hfax.job_submit(); + hfax = null; + */ + } + + } + + + public static void delete_job (string jobid) + { + if (Settings.TransmitAgent == "hylafax") { + hfax = new Hylafax(); + hfax.connect(); + hfax.job_select(jobid); + hfax.job_kill(); + hfax.job_delete(); + hfax = null; + } + + if (Settings.TransmitAgent == "efax") { + gfax.efax.job_kill(jobid); + gfax.efax.job_delete(jobid); + } + + } + + public static int delete_file (string fname) + { + if (Settings.TransmitAgent == "hylafax") { + hfax = new Hylafax(); + hfax.connect(); + int reply = hfax.deletefile(fname); + hfax = null; + return (reply); + } + + if (Settings.TransmitAgent == "efax") { + return(0); + } + return(0); + } + } +} diff --git a/src/gfaxphonebook.cs b/src/gfaxphonebook.cs new file mode 100755 index 0000000..be922c0 --- /dev/null +++ b/src/gfaxphonebook.cs @@ -0,0 +1,498 @@ +// 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. + +namespace gfax { + using Mono.Unix; + using System; + using System.IO; + using GLib; + using Gtk; + using Gnome; + using Glade; + using GConf.PropertyEditors; + using GtkSharp; + using System.Runtime.InteropServices; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + + //************************************************************************ + // GfaxPhonebook class + // + + public class GfaxPhonebook + { + const string APPNAME = "Gfax"; + + const int COLUMN_0 = 0; + const int COLUMN_1 = 1; + const int COLUMN_2 = 2; + const int COLUMN_3 = 3; + const int ALL_COLUMNS = -1; + + string tempName; + string tempNumber; + string tempCompany; + + bool eventsEnabled = true; + + [Glade.Widget] Gtk.Window PhbookWindow; + [Glade.Widget] Gtk.ComboBox PhonebookComboBox; + [Glade.Widget] Gtk.TreeView ItemTreeview; + [Glade.Widget] Gtk.Entry PhonebookComboEntry; + [Glade.Widget] Gtk.Entry EditPhbNumberEntry; + [Glade.Widget] Gtk.Entry EditPhbNameEntry; + [Glade.Widget] Gtk.Entry EditPhbCompanyEntry; + [Glade.Widget] Gtk.ToolButton SaveCloseButton; + [Glade.Widget] Gtk.ToolButton DeletePhonebookButton; + [Glade.Widget] Gtk.Button AddButton; + [Glade.Widget] Gtk.Button UpdateButton; + [Glade.Widget] Gtk.Button ClearButton; + [Glade.Widget] Gtk.Statusbar Statusbar; + + Gtk.ListStore ItemStore; //phonebook item store + G_ListView ItemView; + + GConf.PropertyEditors.EditorShell shell; + Phonebook[] myPhoneBooks; + Glade.XML gxml; + const int id = 1; + bool pbIsReadOnly = false; //wether current phone book is no editable. + + public GfaxPhonebook () + { + myPhoneBooks = Phonetools.get_phonebooks(); + + Application.Init (); + gxml = new Glade.XML (null, "send-druid.glade","PhbookWindow",null); + gxml.Autoconnect (this); + + ItemStore = new ListStore(typeof (string), typeof (string), typeof (string)); + ItemView = new G_ListView(ItemTreeview, ItemStore); + ItemView.AddColumnTitle(Catalog.GetString("Organization"), 0, COLUMN_0); + ItemView.AddColumnTitle(Catalog.GetString("Phone Number"), 1, COLUMN_1); + ItemView.AddColumnTitle(Catalog.GetString("Contact"), 2, COLUMN_2); + ItemTreeview.HeadersVisible = true; + //ItemTreeview.Selection.Mode = SelectionMode.Multiple; + ItemTreeview.Selection.Changed += + new EventHandler(on_ItemTreeview_selection); + + // Populate the drop down combo box with phonebooks and populate + // the list with the first phonebook. + // TODO sort these alphabetically + if ( myPhoneBooks.Length > 0) { + string[] list = new string[myPhoneBooks.Length]; + + if ( myPhoneBooks != null ) { + // populate the list + int i = 0; + PhonebookComboBox.RemoveText(0); + foreach (Phonebook p in myPhoneBooks) { + list[i++] = p.Name; + PhonebookComboBox.AppendText(p.Name); + } + PhonebookComboBox.Active = 0; + } + + //Console.WriteLine(list[PhonebookComboBox.Active]); + DeletePhonebookButton.Sensitive = true; + } else { + DeletePhonebookButton.Sensitive = false; + } + + SaveCloseButton.Sensitive = false; + UpdateButton.Sensitive = false; + ClearButton.Sensitive = false; + AddButton.Sensitive = false; + + Application.Run (); + } + + + private void on_PhbookWindow_delete_event (object o, DeleteEventArgs args) + { + PhbookWindow.Destroy(); + Application.Quit (); + } + + // Menu signals + private void on_New_activate (object o, EventArgs args) + { + on_NewPhonebookButton_clicked(null, null); + } + + private void on_SaveAndClose_activate (object o, EventArgs args) + { + on_SaveCloseButton_clicked(null, null); + } + + private void on_Delete_activate (object o, EventArgs args) + { + on_DeletePhonebookButton_clicked(null, null); + } + + private void on_Close_activate (object o, EventArgs args) + { + on_CloseButton_clicked(null, null); + } + //--------- end of menu ----------------- + + + private void on_NewPhonebookButton_clicked (object o, EventArgs args) + { + // Unselect any phone book otherwise we get gtk errors. + ItemTreeview.Selection.UnselectAll(); + + // run the wizard + NewPhoneBook nphb = new NewPhoneBook (); + nphb.Run(); + + if ( nphb.PhoneBookNames.Count > 0 ) { // don't do this if cancelled + IEnumerator enu = nphb.PhoneBookNames.GetEnumerator(); + + while ( enu.MoveNext() ) { + Phonebook ph = new Phonebook(); + if (nphb.PhoneBookType == "gfax") + ph.Path = gfax.ConfigDirectory + "/" + (string)enu.Current; + else + ph.Path = ""; + + ph.Name = (string)enu.Current; // get the new book name + ph.Type = nphb.PhoneBookType; + Phonetools.add_book(ph); + PhonebookComboBox.AppendText(ph.Name); + } + // Reload the phone books + myPhoneBooks = Phonetools.get_phonebooks(); + + if ( myPhoneBooks.Length > 0) { + //PhonebookComboBox.AppendText(ph.Name); + PhonebookComboBox.Active = 0; + DeletePhonebookButton.Sensitive = true; + } + } + + nphb = null; + } + + private void on_DeletePhonebookButton_clicked (object o, EventArgs args) + { + + if ( myPhoneBooks.Length > 0) { + string[] list = new string[myPhoneBooks.Length]; + + if ( myPhoneBooks != null ) { + // populate the list + int i = 0; + foreach (Phonebook pb in myPhoneBooks) { + list[i++] = pb.Name; + } + } + string book = list[PhonebookComboBox.Active]; + + MessageDialog md = new MessageDialog ( + null, + DialogFlags.DestroyWithParent, + MessageType.Question, + ButtonsType.YesNo, + Catalog.GetString("Are you sure you want to delete the phone book?") + ); + + ResponseType result = (ResponseType)md.Run (); + + if (result == ResponseType.Yes) { + md.Destroy(); + + if (book == null) + return; + Phonetools.delete_book(book); + + PhonebookComboBox.RemoveText(PhonebookComboBox.Active); + ItemStore.Clear(); + + myPhoneBooks = Phonetools.get_phonebooks(); + + if (myPhoneBooks.Length > 0) { + // now reload + PhonebookComboBox.Active = 0; + on_PhonebookComboBox_changed(null, null); + } else { + DeletePhonebookButton.Sensitive = false; + PhonebookComboBox.InsertText(0," "); + } + PhonebookComboBox.Active = 0; + + } else { + md.Destroy(); + } + } + } + + private void on_SaveCloseButton_clicked (object o, EventArgs args) + { + ArrayList rows; + ArrayList contacts = new ArrayList(); + string book; + + if ( myPhoneBooks.Length > 0) { + string[] list = new string[myPhoneBooks.Length]; + + if ( myPhoneBooks != null ) { + // populate the list + int i = 0; + foreach (Phonebook pb in myPhoneBooks) + list[i++] = pb.Name; + } + book = list[PhonebookComboBox.Active]; + + // just get all items and save + SaveCloseButton.Sensitive = false; + //eventsEnabled = false; + EditPhbCompanyEntry.Text = ""; + EditPhbNumberEntry.Text = ""; + EditPhbNameEntry.Text = ""; + + rows = ItemView.GetAllRows(); + + IEnumerator enu = rows.GetEnumerator(); + while ( enu.MoveNext() ) { + GfaxContact c = new GfaxContact(); + c.Organization = ((string[])enu.Current)[0]; + c.PhoneNumber = ((string[])enu.Current)[1]; + c.ContactPerson = ((string[])enu.Current)[2]; + contacts.Add(c); + } + + Phonetools.save_phonebook_items(book, contacts); + //EditPhbList.Selection.UnselectAll(); + } + + PhbookWindow.Destroy(); + Application.Quit (); + } + + private void on_CloseButton_clicked (object o, EventArgs args) + { + if (SaveCloseButton.Sensitive) { + MessageDialog md = new MessageDialog ( + null, + DialogFlags.DestroyWithParent, + MessageType.Question, + ButtonsType.YesNo, + Catalog.GetString("You have unsaved phone book entries.\n Are you sure you want to Quit?") + ); + + ResponseType result = (ResponseType)md.Run (); + + if (result == ResponseType.Yes) { + md.Destroy(); + PhbookWindow.Destroy(); + Application.Quit (); + } else { + md.Destroy(); + } + } else { + PhbookWindow.Destroy(); + Application.Quit (); + } + } + + + private void on_PhonebookComboBox_changed (object o, EventArgs args) + { + ArrayList contacts = null; + Phonebook p; + + // get the first book in the list and load the liststore + if ( myPhoneBooks.Length > 0) { + string[] list = new string[myPhoneBooks.Length]; + + if ( myPhoneBooks != null ) { + // populate the list + int i = 0; + foreach (Phonebook pb in myPhoneBooks) { + list[i++] = pb.Name; + } + } + + p = Phonetools.get_book_from_name(list[PhonebookComboBox.Active]); + if (p == null) + return; + + // Clear the list_store + ItemStore.Clear(); + + contacts = Phonetools.get_contacts(p); + + if (contacts != null) { + IEnumerator enu = contacts.GetEnumerator(); + while ( enu.MoveNext() ) { + GfaxContact c = new GfaxContact(); + c = (GfaxContact)enu.Current; + ItemView.AddTextToRow(c.Organization, c.PhoneNumber, c.ContactPerson); + } + if (p.Type == "evolution") { + pbIsReadOnly = true; + EditPhbCompanyEntry.Sensitive = false; + EditPhbNumberEntry.Sensitive = false; + EditPhbNameEntry.Sensitive = false; + + } else { + pbIsReadOnly = false; + EditPhbCompanyEntry.Sensitive = true; + EditPhbNumberEntry.Sensitive = true; + EditPhbNameEntry.Sensitive = true; + eventsEnabled = true; + } + } + } + } + + private void on_EditPhbNumberEntry_changed (object o, EventArgs args) + { + if (eventsEnabled) { + ArrayList al = ItemView.GetSelections(ALL_COLUMNS); + // if single contact selected + if (al.Count > 0) { + UpdateButton.Sensitive = true; + } else { + AddButton.Sensitive = true; + ClearButton.Sensitive = true; + } + } + } + private void on_EditPhbNameEntry_changed (object o, EventArgs args) + { + if (eventsEnabled) { + ArrayList al = ItemView.GetSelections(ALL_COLUMNS); + // if single contact selected + if (al.Count > 0) { + UpdateButton.Sensitive = true; + } else { + AddButton.Sensitive = true; + ClearButton.Sensitive = true; + } + } + } + private void on_EditPhbCompanyEntry_changed (object o, EventArgs args) + { + if (eventsEnabled) { + ArrayList al = ItemView.GetSelections(ALL_COLUMNS); + // if single contact selected + if (al.Count > 0) { + UpdateButton.Sensitive = true; + } else { + AddButton.Sensitive = true; + ClearButton.Sensitive = true; + } + } + } + + private void on_ClearButton_clicked (object o, EventArgs args) + { + eventsEnabled = false; + EditPhbCompanyEntry.Text = ""; + EditPhbNumberEntry.Text = ""; + EditPhbNameEntry.Text = ""; + UpdateButton.Sensitive = false; + ItemTreeview.Selection.UnselectAll(); + ClearButton.Sensitive = false; + AddButton.Sensitive = false; + Statusbar.Pop(id); + Statusbar.Push(id, " "); + } + + private void on_AddButton_clicked (object o, EventArgs args) + { + ItemView.AddTextToRow(EditPhbCompanyEntry.Text, + EditPhbNumberEntry.Text, + EditPhbNameEntry.Text); + + eventsEnabled = false; // no updates till selected + EditPhbCompanyEntry.Text = ""; + EditPhbNumberEntry.Text = ""; + EditPhbNameEntry.Text = ""; + EditPhbNumberEntry.HasFocus = true; + SaveCloseButton.Sensitive = true; + ClearButton.Sensitive = false; + AddButton.Sensitive = false; + eventsEnabled = true; + } + + private void on_UpdateButton_clicked (object o, EventArgs args) + { + ItemView.UpdateColumnText(tempNumber, EditPhbNumberEntry.Text, COLUMN_1); + ItemView.UpdateColumnText(tempName, EditPhbNameEntry.Text, COLUMN_2); + ItemView.UpdateColumnText(tempCompany, EditPhbCompanyEntry.Text, COLUMN_0); + EditPhbCompanyEntry.Text = ""; + EditPhbNumberEntry.Text = ""; + EditPhbNameEntry.Text = ""; + UpdateButton.Sensitive = false; + ItemTreeview.Selection.UnselectAll(); + ClearButton.Sensitive = false; + SaveCloseButton.Sensitive = true; + Statusbar.Pop(id); + Statusbar.Push(id, " "); + } + + private void on_ItemTreeview_selection (object o, EventArgs args) + { + ArrayList al; + + eventsEnabled = false; // no updates + if (!pbIsReadOnly) { + al = ItemView.GetSelections(ALL_COLUMNS); + Statusbar.Push(id,Catalog.GetString("Press the <DELETE> key to delete an entry.")); + + // if single contact selected + if (al.Count == 3) { + IEnumerator enu = al.GetEnumerator(); + enu.MoveNext(); + EditPhbCompanyEntry.Text = (string)enu.Current; + tempCompany = (string)enu.Current; + enu.MoveNext(); + EditPhbNumberEntry.Text = (string)enu.Current; + tempNumber = (string)enu.Current; + enu.MoveNext(); + EditPhbNameEntry.Text = (string)enu.Current; + tempName = (string)enu.Current; + } + AddButton.Sensitive = false; + ClearButton.Sensitive = true; + eventsEnabled = true; + } + } + + private void on_ItemTreeview_key_press_event (object o, KeyPressEventArgs args) + { + if (args.Event.Key == Gdk.Key.Delete ) { + + //eventsEnabled = false; // no updates + ArrayList al = ItemView.GetSelections(ALL_COLUMNS); + + // if single contact selected + //if (al.Count == 3) { + ItemView.RemoveSelectedRow(); + EditPhbCompanyEntry.Text = ""; + EditPhbNumberEntry.Text = ""; + EditPhbNameEntry.Text = ""; + //} + AddButton.Sensitive = false; + ClearButton.Sensitive = false; + SaveCloseButton.Sensitive = true; + //eventsEnabled = true; + } + } + } +} diff --git a/src/gfaxprefs.cs b/src/gfaxprefs.cs new file mode 100755 index 0000000..0ff9e6d --- /dev/null +++ b/src/gfaxprefs.cs @@ -0,0 +1,302 @@ +// GFAX - Gnome fax application +// Copyright (C) 2003 - 2008 George A. Farris +// +// 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 3 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. + +namespace gfax { + using Mono.Unix; + using System; + using System.IO; + using GLib; + using Gtk; + using Gnome; + using Glade; + using GConf.PropertyEditors; + using GtkSharp; + using System.Runtime.InteropServices; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + + //************************************************************************ + // GfaxPrefs class + // + // This is the preferences window. + public class GfaxPrefs + { + Glade.XML gxml; + [Glade.Widget] Gtk.Dialog PrefsDialog; + [Glade.Widget] Gtk.Notebook PrefsNotebook; + //System Tab + [Glade.Widget] Gtk.RadioButton HylafaxRadioButton; + [Glade.Widget] Gtk.RadioButton EfaxRadioButton; + [Glade.Widget] Gtk.Entry FaxNumberEntry; + [Glade.Widget] Gtk.Entry DialPrefixEntry; + [Glade.Widget] Gtk.Entry ModemEntry; + [Glade.Widget] Gtk.Entry FaxViewerEntry; + + //Hylafax Tab + [Glade.Widget] Gtk.Entry HylafaxHostnameEntry; + [Glade.Widget] Gtk.Entry HylafaxPortEntry; + [Glade.Widget] Gtk.Entry HylafaxUsernameEntry; + + //Efax Tab + [Glade.Widget] Gtk.Entry EfaxModemDeviceEntry; + [Glade.Widget] Gtk.ComboBox EfaxPapersizeComboBox; + [Glade.Widget] Gtk.ComboBox EfaxModemTypeComboBox; + [Glade.Widget] Gtk.ComboBox EfaxModemSpeakerVolumeComboBox; + + //User Tab + [Glade.Widget] Gtk.CheckButton EmailNotifyCheckButton; + [Glade.Widget] Gtk.Entry EmailAddressEntry; + [Glade.Widget] Gtk.CheckButton SendNowCheckButton; + [Glade.Widget] Gtk.CheckButton FaxLogCheckButton; + [Glade.Widget] Gtk.CheckButton CoverPageCheckButton; + [Glade.Widget] Gtk.CheckButton HiResCheckButton; + + // we set this otherwise setting inital values will wipe + // out all the other settings. + bool eventsEnabled = false; + + bool taChanged = false; + + const int HYLAFAX_PAGE = 1; + const int EFAX_PAGE = 2; + + string[] papersize = {"letter", "legal", "a4"}; + + string[] modemType = {@"-j\Q4",@"-j\Q1",@"-j*F1",@"-j&H2&I0&R1&D3I4",@"-or"}; + /* + # FCINIT='-j\Q4' # AT&T (Dataport, Paradyne) + # FCINIT='-j\Q1' # Motorola (Power Modem, 3400 Pro,...) + # FCINIT='-j*F1' # QuickComm (Spirit II) + # FCINIT='-j&H2&I0&R1&D3I4' # USR (Courier, Sportster) + # FCINIT='-or' # Multi-Tech (for bit reversal) + */ + + + public GfaxPrefs () + { + gxml = new Glade.XML (null, "gfax.glade","PrefsDialog",null); + //GConf.PropertEditors + EditorShell shell = new EditorShell (gxml); + gxml.Autoconnect(this); + + + // System Tab + if (Settings.TransmitAgent == "hylafax") { + HylafaxRadioButton.Active = true; + CoverPageCheckButton.Visible = false; + PrefsNotebook.GetNthPage(EFAX_PAGE).Hide(); + } + else if (Settings.TransmitAgent == "efax") { + EfaxRadioButton.Active = true; + EmailNotifyCheckButton.Sensitive = false; + EmailAddressEntry.Sensitive = false; + Settings.SendNow = SendNowCheckButton.Active; + FaxLogCheckButton.Visible = false; + CoverPageCheckButton.Visible = false; + Settings.HiResolution = HiResCheckButton.Active; + + PrefsNotebook.GetNthPage(HYLAFAX_PAGE).Hide(); + } + + // Set these regardless so they are set if we need them + switch (Settings.EfaxPapersize) { + case "letter": + EfaxPapersizeComboBox.Active = 0; + break; + case "legal": + EfaxPapersizeComboBox.Active = 1; + break; + case "a4": + EfaxPapersizeComboBox.Active = 2; + break; + default: + EfaxPapersizeComboBox.Active = 0; + break; + } + //"-j\\Q4","-j\\Q1","-j*F1","-j&H2&I0&R1&D3I4","-or" + switch (Settings.EfaxModemFcinit) { + case @"-j\Q4": + EfaxModemTypeComboBox.Active = 0; + break; + case @"-j\Q1": + EfaxModemTypeComboBox.Active = 1; + break; + case @"-j*F1": + EfaxModemTypeComboBox.Active = 2; + break; + case @"-j&H2&I0&R1&D3I4": + EfaxModemTypeComboBox.Active = 3; + break; + case @"-or": + EfaxModemTypeComboBox.Active = 4; + break; + default: + EfaxModemTypeComboBox.Active = 5; + break; + } + + EfaxModemSpeakerVolumeComboBox.Active = Settings.EfaxModemSpeakerVolume; + + + + // changes that happen automagically + shell.Add(SettingKeys.FaxNumber, "FaxNumberEntry"); + shell.Add(SettingKeys.PhonePrefix, "DialPrefixEntry"); + shell.Add(SettingKeys.FaxViewer, "FaxViewerEntry"); + + // Hylafax Tab + shell.Add(SettingKeys.Hostname, "HylafaxHostnameEntry"); + shell.Add(SettingKeys.Port, "HylafaxPortEntry"); + shell.Add(SettingKeys.Username, "HylafaxUsernameEntry"); + + // Efax Tab + shell.Add(SettingKeys.EfaxModemDevice, "EfaxModemDeviceEntry"); + + + // User tab + shell.Add(SettingKeys.EmailNotify, "EmailNotifyCheckButton"); + shell.Add(SettingKeys.EmailAddress, "EmailAddressEntry"); + shell.Add(SettingKeys.SendNow, "SendNowCheckButton"); + shell.Add(SettingKeys.LogEnabled, "FaxLogCheckButton"); + shell.Add(SettingKeys.CoverPage, "CoverPageCheckButton"); + shell.Add(SettingKeys.HiResolution, "HiResCheckButton"); + + eventsEnabled = true; + + } + + + private void on_PrefsDialog_delete_event (object o, DeleteEventArgs args) + { + MessageDialog md; + if (taChanged) { + md = new MessageDialog ( + null, + DialogFlags.DestroyWithParent, + MessageType.Warning, + ButtonsType.Ok, + Catalog.GetString("You need to exit Gfax and restart it when you change transport agents") + ); + md.Run (); + md.Destroy(); + } + PrefsDialog.Destroy(); + args.RetVal = true; + } + + private void on_CloseButton_clicked (object o, EventArgs args) + { + MessageDialog md; + if (taChanged) { + md = new MessageDialog ( + null, + DialogFlags.DestroyWithParent, + MessageType.Warning, + ButtonsType.Ok, + Catalog.GetString("You need to exit Gfax and restart it when you change transport agents") + ); + md.Run (); + md.Destroy(); + } + PrefsDialog.Destroy(); + } + + private void on_HelpButton_clicked (object o, EventArgs args) + { + + } + + private void system_tab_changed (object o, EventArgs args) + { + if (eventsEnabled) { + //eventsEnabled = false; + if (HylafaxRadioButton.Active) { + Settings.TransmitAgent = "hylafax"; + Settings.RefreshQueueInterval = 30; + Settings.RefreshQueueEnabled = false; + PrefsNotebook.GetNthPage(HYLAFAX_PAGE).Show(); + PrefsNotebook.GetNthPage(EFAX_PAGE).Hide(); + } + else if (EfaxRadioButton.Active) { + Settings.TransmitAgent = "efax"; + Settings.RefreshQueueInterval = 15; + Settings.RefreshQueueEnabled = true; + PrefsNotebook.GetNthPage(EFAX_PAGE).Show(); + PrefsNotebook.GetNthPage(HYLAFAX_PAGE).Hide(); + + } + + Settings.FaxNumber = FaxNumberEntry.Text; + Settings.PhonePrefix = DialPrefixEntry.Text; + Settings.FaxViewer = FaxViewerEntry.Text; + } + } + + private void user_tab_changed (object o, EventArgs args) + { + if (eventsEnabled) { + Settings.EmailNotify = EmailNotifyCheckButton.Active; + Settings.EmailAddress = EmailAddressEntry.Text; + Settings.SendNow = SendNowCheckButton.Active; + Settings.LogEnabled = FaxLogCheckButton.Active; + Settings.CoverPage = CoverPageCheckButton.Active; + Settings.HiResolution = HiResCheckButton.Active; + } + } + + private void radio_button_toggled (object o, EventArgs args) + { + if (eventsEnabled) + taChanged = true; + } + + + private void efax_setup_changed (object o, EventArgs args) + { + + if (eventsEnabled) { + // Option 5 is custom define so we don't change anything + if (EfaxModemTypeComboBox.Active != 5) { + switch (EfaxModemTypeComboBox.Active) { + case 0: + Settings.EfaxModemFcinit = @"-j\Q4"; + break; + case 1: + Settings.EfaxModemFcinit = @"-j\Q1"; + break; + case 2: + Settings.EfaxModemFcinit = @"-j*F1"; + break; + case 3: + Settings.EfaxModemFcinit = @"-j&H2&I0&R1&D3I4"; + break; + case 4: + Settings.EfaxModemFcinit = @"-or"; + break; + default: + Settings.EfaxModemFcinit = @"-j&H2&I0&R1&D3I4"; + break; + } + } + + Settings.EfaxPapersize = EfaxPapersizeComboBox.ActiveText; + Settings.EfaxModemSpeakerVolume = EfaxModemSpeakerVolumeComboBox.Active; + } + } + } +} diff --git a/src/gfaxsend.cs b/src/gfaxsend.cs new file mode 100644 index 0000000..444ed91 --- /dev/null +++ b/src/gfaxsend.cs @@ -0,0 +1,364 @@ +// 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. + +//************************************************************************ +// GfaxSend class +// +// This is a the send window for sending of a facsimile. +namespace gfax { + using Mono.Unix; + using System; + using System.IO; + using GLib; + using Gtk; + using Gnome; + using Glade; + using GConf.PropertyEditors; + using GtkSharp; + using System.Runtime.InteropServices; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + + + public class GfaxSend // : Program + { + const string APPNAME = "Gfax"; + + const int COLUMN_0 = 0; + const int COLUMN_1 = 1; + const int COLUMN_2 = 2; + const int COLUMN_3 = 3; + const int ALL_COLUMNS = -1; + + [Glade.Widget] Gtk.Window NewFaxDialog; + [Glade.Widget] Gtk.Button BrowseButton; + [Glade.Widget] Gtk.Button PhoneButton; + [Glade.Widget] Gtk.Entry NumberEntry; + [Glade.Widget] Gtk.Entry EmailEntry; + [Glade.Widget] Gtk.Entry FilenameEntry; + [Glade.Widget] Gtk.CheckButton ResolutionCheckbutton; + [Glade.Widget] Gtk.CheckButton EmailCheckbutton; + [Glade.Widget] Gtk.CheckButton SendCheckbutton; + [Glade.Widget] Gtk.TreeView ItemTreeview; + [Glade.Widget] Gnome.DateEdit SendDateedit; + //[Glade.Widget] Gnome.FileEntry PSFileEntry; + + + Gtk.ListStore ItemStore; + G_ListView ItemListview; + + GConf.PropertyEditors.EditorShell shell; + + Glade.XML gxml; + string filename, includeFilename; + bool dosend; + + public GfaxSend (string fname, string[] args) + { + + filename = fname; + includeFilename = args[0]; + + Application.Init (); + + if (Settings.Faxtracing == true) { + Console.WriteLine("[GfaxSend] File name is : {0}", fname); + } + + // check to see if we've run before, if so gfax will be there + if ( Settings.RunSetupAtStart ) { + Settings.RunSetupAtStart = false; + MessageDialog md; + md = new MessageDialog ( + null, + DialogFlags.DestroyWithParent, + MessageType.Info, + ButtonsType.Ok, + Catalog.GetString( + @" +This is the first time you have run Gfax. +Please run Gfax from the menu or command line and set your +MODEM TYPE, PORT and Fax number under preferences. + +Gfax is initially setup to use Efax, you may change it use +Hylafax if you prefer or require connection to a network +facsimile server.") + ); + md.Run (); + md.Destroy(); + Application.Quit(); + dosend = false; + Environment.Exit(0); + } +/* + if ( Settings.FaxNumber.Length <= 4 ) { + MessageDialog md; + md = new MessageDialog ( + null, + DialogFlags.DestroyWithParent, + MessageType.Info, + ButtonsType.Ok, + Catalog.GetString( + @" +You must have a Fax number set in your preferences under +Phone Information.") + ); + md.Run (); + md.Destroy(); + //Application.Quit(); + dosend = false; + return; + } +*/ + gxml = new Glade.XML (null, "send-druid.glade","NewFaxDialog",null); + gxml.Autoconnect (this); + + // Set the program icon + //Gdk.Pixbuf Icon = new Gdk.Pixbuf(null, "gfax.png"); + //((Gtk.Window) gxml["NewFaxDialog"]).Icon = Icon; + //NewFaxDialog.Icon = Icon; + + ItemStore = new ListStore( + typeof (Boolean), + typeof (string), + typeof (string), + typeof (string)); + + ItemListview = new G_ListView(ItemTreeview, ItemStore); + + ItemListview.AddColumnTitleToggle(Catalog.GetString("Send"), 0, COLUMN_0); + ItemListview.AddColumnTitle(Catalog.GetString("Phone Number"), 0, COLUMN_1); + ItemListview.AddColumnTitle(Catalog.GetString("Organization"), 0, COLUMN_2); + ItemListview.AddColumnTitle(Catalog.GetString("Contact"), 0, COLUMN_3); + + ItemTreeview.HeadersVisible = true; + + //ItemTreeview.Selection.Mode = SelectionMode.Multiple; + + ResolutionCheckbutton.Active = Settings.HiResolution; + EmailCheckbutton.Active = Settings.EmailNotify; + EmailEntry.Text = Settings.EmailAddress; + + if (Settings.TransmitAgent == "efax") { + EmailCheckbutton.Visible = false; + EmailEntry.Visible = false; + SendCheckbutton.Visible = false; + SendDateedit.Visible = false; + } + + if (SendCheckbutton.Active) + SendDateedit.Sensitive = false; + + // If we have a file name from the gnome print dialog + if (includeFilename != "do_filename") { + FilenameEntry.Text = Catalog.GetString("Spooled from print job"); + FilenameEntry.Sensitive = false; + BrowseButton.Sensitive = false; + } + + Application.Run (); + } + + public bool DoSend + { + get { return dosend; } + } + + public string Filename + { + get { return filename; } + } + + + private void on_window1_delete_event (object o, DeleteEventArgs args) + { + dosend = false; + //((Gtk.Window) gxml["NewFaxDialog"]).Destroy(); + NewFaxDialog.Destroy(); + Application.Quit (); + args.RetVal = true; + } + + private void on_CancelButton_clicked (object o, EventArgs args) + { + dosend = false; + //((Gtk.Window) gxml["NewFaxDialog"]).Destroy(); + NewFaxDialog.Destroy(); + Application.Quit (); + } + + private void on_NumberEntry_changed (object o, EventArgs args) + { + //if (NumberEntry.Text == "\t") + //((Gnome.Druid) gxml["send_druid"]).HasFocus = true; + } + + private void on_SendCheckButton_toggled (object o, EventArgs args) + { + SendDateedit.Sensitive = ! SendDateedit.Sensitive; + } + + private void on_NumberEntry_activate (object o, EventArgs args) + { + Gtk.TreeIter iter = new Gtk.TreeIter(); + + iter = ItemStore.AppendValues(true, NumberEntry.Text, "", ""); + ItemTreeview.Model = ItemStore; + NumberEntry.Text = ""; + } + + + private void on_BrowseButton_clicked (object o, EventArgs args) + { + FileChooserDialog fc = new FileChooserDialog("Choose postscript file", null, FileChooserAction.Open); + fc.AddButton (Gtk.Stock.Cancel, Gtk.ResponseType.Cancel); + fc.AddButton (Gtk.Stock.Open, Gtk.ResponseType.Ok); + + ResponseType result = (ResponseType)fc.Run (); + + if (result == ResponseType.Ok) { + FilenameEntry.Text = fc.Filename; + fc.Destroy(); + } else { + fc.Destroy(); + } + } + + + private void on_PhoneButton_clicked (object o, EventArgs args) + { + Gtk.TreeIter iter = new Gtk.TreeIter(); + // display the phone book, when we return gfax.Destinations + // will be set with contacts. + GfaxSendPhoneBook gfs = new GfaxSendPhoneBook(gxml, "gfaxsend"); + + ItemStore.Clear(); + + if (gfax.Destinations.Count > 0) { + IEnumerator enu = gfax.Destinations.GetEnumerator(); + + while ( enu.MoveNext() ) { + iter = ItemStore.AppendValues(true, + ((GfaxContact)enu.Current).PhoneNumber, + ((GfaxContact)enu.Current).Organization, + ((GfaxContact)enu.Current).ContactPerson); + ItemTreeview.Model = ItemStore; + } + } + } + + + // When finished gfax.Destinations will contain a list of contacts + // of Phonebook.Contact type. + private void on_SendfaxButton_clicked (object o, EventArgs args) + { + Gtk.TreeIter iter = new Gtk.TreeIter(); + ArrayList rows = new ArrayList(); + + if (includeFilename == "do_filename") + filename = FilenameEntry.Text; + + if (!File.Exists(filename)) { + MessageDialog md; + md = new MessageDialog (null, DialogFlags.DestroyWithParent, + MessageType.Info, ButtonsType.Ok, + Catalog.GetString( + @" +The file you have entered does not exist. +Please check the name and try again.") + ); + md.Run (); + md.Destroy(); + return; + } + + // clear all the distinations, it's a little wierd yup + gfax.Destinations.Clear(); + + // Get the first row. + ItemStore.GetIterFirst(out iter); + + try { + if ( (bool)ItemStore.GetValue(iter, 0) ) { // if send is true (toggle set) + + GfaxContact c = new GfaxContact(); + c.PhoneNumber = (string)ItemStore.GetValue(iter, 1); // number + c.Organization = (string)ItemStore.GetValue(iter, 2); // organization + c.ContactPerson = (string)ItemStore.GetValue(iter, 3); // contact + + rows.Add(c); + } + } + catch (Exception e) { + MessageDialog md; + md = new MessageDialog ( + null, + DialogFlags.DestroyWithParent, + MessageType.Info, + ButtonsType.Ok, + Catalog.GetString( + @" +You have not entered a facsimile number! +Please enter a number and press the <i><b>Enter</b></i> key or +click the <i><b>Phone Book</b></i> button to select numbers or +entire phone books.") + ); + md.Run (); + md.Destroy(); + return; + } + + // get the rest of the rows + while (ItemStore.IterNext(ref iter)) { + + try { + if ( (bool)ItemStore.GetValue(iter, 0) ) { // if send is true (toggle set) + + GfaxContact c = new GfaxContact(); + c.PhoneNumber = (string)ItemStore.GetValue(iter, 1); // number + c.Organization = (string)ItemStore.GetValue(iter, 2); // organization + c.ContactPerson = (string)ItemStore.GetValue(iter, 3); // contact + + rows.Add(c); + } + } + catch (Exception e) {} + } + + + if (SendCheckbutton.Active) { + gfax.timeToSend = DateTime.UtcNow; + } else { + // Convert to UTC for Hylafax + gfax.timeToSend = (SendDateedit.Time).ToUniversalTime(); + } + + gfax.Destinations = rows; + + //get the fine resolution status + gfax.sendWizardResolution = ResolutionCheckbutton.Active; + //get the email flag and email address + gfax.sendWizardEmailNotify = EmailCheckbutton.Active; + gfax.sendWizardEmailAddress = EmailEntry.Text; + + if ( gfax.Destinations.Count > 0 ) + dosend = true; // yes send the fax + + //((Gtk.Window) gxml["NewFaxDialog"]).Hide(); + NewFaxDialog.Hide(); + Application.Quit(); + } + } +} diff --git a/src/gui.cs b/src/gui.cs new file mode 100755 index 0000000..b5ab51a --- /dev/null +++ b/src/gui.cs @@ -0,0 +1,1137 @@ +// GFAX - Gnome fax application +// Copyright (C) 2003 - 2008 George A. Farris +// +// 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 3 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 Library 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. + +//#define DEBUG + +namespace gfax { + using Mono.Unix; + using System; + using System.IO; + using GLib; + using Gdk; + using Gtk; + using Gnome; + using Glade; + using GConf.PropertyEditors; + using GtkSharp; + using System.Runtime.InteropServices; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + + + //************************************************************************ + // Gfax class + // + // This is the main application window + + public class Gfax : Program + { + const string VERSION = "0.7.7"; + const string NAME = "Gfax"; + const string APPNAME = "Gfax"; + + // Notebook pages + const int SENDQ_PAGE = 0; + const int DONEQ_PAGE = 1; + const int RECEIVEQ_PAGE = 2; + + const int COLUMN_0 = 0; + const int COLUMN_1 = 1; + const int COLUMN_2 = 2; + const int COLUMN_3 = 3; + const int COLUMN_4 = 4; + const int COLUMN_5 = 5; + const int ALL_COLUMNS = -1; + + // Strings to hold old contact info temporarily + string tempName; + string tempNumber; + string tempCompany; + + ArrayList oldSendQueue = null; // hold old queue results + + bool restart = true; + bool eventsEnabled = true; + bool queueBusy = false; + + enum ActiveQ { done, send, receive }; + ActiveQ activeQ; + + + Glade.XML gxml; + + [Glade.Widget] Gtk.Window GfaxWindow; + [Glade.Widget] Gnome.AppBar Appbar; + + [Glade.Widget] Gtk.TreeView StatusList; + [Glade.Widget] Gtk.TreeView JobsCompleteList; + [Glade.Widget] Gtk.TreeView JobsReceivedList; + [Glade.Widget] Gtk.Notebook StatusNotebook; + [Glade.Widget] Gtk.Button DeleteJobButton; + [Glade.Widget] Gtk.Button ModifyJobButton; + [Glade.Widget] Gtk.Button ViewPrintButton; + [Glade.Widget] Gtk.Button RecvfaxDeleteButton; + [Glade.Widget] Gtk.TextView StatusText; + + + // Menu items + [Glade.Widget] Gtk.CheckMenuItem AutoQRefreshCheckMenuItem; + [Glade.Widget] Gtk.CheckMenuItem EmailNotificationCheckMenuItem; + [Glade.Widget] Gtk.CheckMenuItem HiResolutionModeCheckMenuItem; + [Glade.Widget] Gtk.CheckMenuItem LogEnabledCheckMenuItem; + [Glade.Widget] Gtk.CheckMenuItem FaxTracingCheckMenuItem; + + //Gtk.Window MainWindow; + + Gtk.ListStore StatusStore; + Gtk.ListStore RecvStore; + Gtk.TreeModel StatusModel; + G_ListView lv, jobsCompletedView, jobsReceivedView; + + // text buffer for status text area + TextBuffer StatusTextBuffer = new TextBuffer(new TextTagTable()); + + Phonebook[] myPhoneBooks; + + GConf.PropertyEditors.EditorShell shell; + + long filePos = 0; + static bool iconified = true; // gfax starts iconified + + static long lastMaxOffset; + + + + public Gfax (string fname, string[] args) + : base (APPNAME, VERSION, Modules.UI, args, new object [0]) + { + //Phonebook[] pb; delete me + + // Set the program icon + Gtk.Window.DefaultIconName = "gfax"; + + Application.Init (); + + // check to see if we've run before, if so gfax will be there + if ( Settings.RunSetupAtStart ) { + Settings.RunSetupAtStart = false; + + MessageDialog md; + md = new MessageDialog ( + null, + DialogFlags.DestroyWithParent, + MessageType.Info, + ButtonsType.Ok, + Catalog.GetString( + @" +This is the first time you have run Gfax. +You should set your MODEM TYPE and PORT under preferences. + +Gfax is initially setup to use Efax, you may change it use +Hylafax if you prefer or require connection to a network +facsimile server.") + ); + md.Run (); + md.Destroy(); + } + + if (!Directory.Exists(gfax.SpoolDirectory)) { + G_Message gm = new G_Message(Catalog.GetString( + @"Your spool directory is missing! + +Please login as the root user and create the " ++ gfax.SpoolDirectory + +" directory.\n\nAll users should be able to write to it.\n")); + return; + } + if (!Directory.Exists(gfax.SpoolDirectory + "/doneq")) { + G_Message gm = new G_Message(Catalog.GetString( + @"The doneq directory is missing in your spool directory! + +Please login as the root user and create the " ++ gfax.SpoolDirectory + "/doneq" + +" directory.\n\nAll users should be able to write to it.\n")); + return; + } + if (!Directory.Exists(gfax.SpoolDirectory + "/recq")) { + G_Message gm = new G_Message(Catalog.GetString( + @"The recq directory is missing in your spool directory! + +Please login as the root user and create the " ++ gfax.SpoolDirectory + "/recq" + +" directory.\n\nAll users should be able to write to it.\n")); + return; + } + + + gxml = new Glade.XML (null, "gfax.glade", "GfaxWindow", null); + gxml.Autoconnect (this); + + + // Set initial gui state as per preferences + // GConf.PropertyEditors.EditorShell doesn't handle + // checkmenuitems; + eventsEnabled = false; + if (Settings.TransmitAgent == "hylafax") { + AutoQRefreshCheckMenuItem.Active = Settings.RefreshQueueEnabled; + EmailNotificationCheckMenuItem.Active = Settings.EmailNotify; + HiResolutionModeCheckMenuItem.Active = Settings.HiResolution; + LogEnabledCheckMenuItem.Active = Settings.LogEnabled; + } + if (Settings.TransmitAgent == "efax") { + AutoQRefreshCheckMenuItem.Active = Settings.RefreshQueueEnabled; + AutoQRefreshCheckMenuItem.Sensitive = false; + EmailNotificationCheckMenuItem.Active = false; + EmailNotificationCheckMenuItem.Sensitive = false; + HiResolutionModeCheckMenuItem.Active = Settings.HiResolution; + LogEnabledCheckMenuItem.Visible = false; + } + eventsEnabled = true; + + StatusText.Editable = false; + StatusText.CanFocus = false; + StatusText.Buffer = StatusTextBuffer; + + // Set the program icon + Gdk.Pixbuf Icon = new Gdk.Pixbuf(null, "gfax.png"); + + gfax.MainWindow = GfaxWindow; + + // Setup listview icons + InitListViewIcons(); + + StatusStore = new ListStore( + typeof (Gdk.Pixbuf), + typeof (string), + typeof (string), + typeof (string), + typeof (string), + typeof (string), + typeof (string), + typeof (DateTime), + typeof (string)); + + RecvStore = new ListStore( + typeof (Gdk.Pixbuf), + typeof (string), + typeof (string), + typeof (string), + typeof (DateTime), + typeof (string)); + + + lv = new G_ListView(StatusList, StatusStore); + lv.AddColumnIcon(Gtk.Stock.Info, 0); + lv.AddColumnTitle(Catalog.GetString("Jobid"), 1, 1); + lv.AddColumnTitle(Catalog.GetString("Number"), 2, 2); + lv.AddColumnTitle(Catalog.GetString("Status"), 3, 3); + lv.AddColumnTitle(Catalog.GetString("Owner"), 4, 4); + lv.AddColumnTitle(Catalog.GetString("Pages"), 5, 5); + lv.AddColumnTitle(Catalog.GetString("Dials"), 6, 6); + lv.AddColumnDateTime(Catalog.GetString("Send At"), "G", 7, 7); + lv.AddColumnTitle(Catalog.GetString("Information"), 8, 8); + + // List view for completed jobs tab + jobsCompletedView = new G_ListView(JobsCompleteList, StatusStore); + jobsCompletedView.AddColumnIcon(Gtk.Stock.Info, 0); + jobsCompletedView.AddColumnTitle(Catalog.GetString("Jobid"), 1, 1); + jobsCompletedView.AddColumnTitle(Catalog.GetString("Number"), 2, 2); + jobsCompletedView.AddColumnTitle(Catalog.GetString("Status"), 3, 3); + jobsCompletedView.AddColumnTitle(Catalog.GetString("Owner"), 4, 4); + jobsCompletedView.AddColumnTitle(Catalog.GetString("Pages"), 5, 5); + jobsCompletedView.AddColumnTitle(Catalog.GetString("Dials"), 6, 6); + jobsCompletedView.AddColumnDateTime(Catalog.GetString("Send At"), "G", 7, 7); + jobsCompletedView.AddColumnTitle(Catalog.GetString("Information"), 8, 8); + + jobsReceivedView = new G_ListView(JobsReceivedList, RecvStore); + jobsReceivedView.AddColumnIcon(Gtk.Stock.Info, 0); + jobsReceivedView.AddColumnTitle(Catalog.GetString("Sender"), 1, 1); + jobsReceivedView.AddColumnTitle(Catalog.GetString("Status"), 2, 2); + jobsReceivedView.AddColumnTitle(Catalog.GetString("Pages "), 3, 3); + jobsReceivedView.AddColumnDateTime(Catalog.GetString("Arrived"), "d", 4, 4); + jobsReceivedView.AddColumnTitle(Catalog.GetString("Filename"), 5, 5); + + StatusList.Selection.Changed += + new EventHandler(on_StatusList_selection); + StatusList.Selection.Mode = SelectionMode.Multiple; + StatusList.HeadersVisible = true; + + JobsCompleteList.Selection.Changed += + new EventHandler(on_JobsCompleteList_selection); + JobsCompleteList.Selection.Mode = SelectionMode.Multiple; + JobsCompleteList.HeadersVisible = true; + + JobsReceivedList.Selection.Changed += + new EventHandler(on_JobsReceivedList_selection); + JobsReceivedList.Selection.Mode = SelectionMode.Multiple; + JobsReceivedList.HeadersVisible = true; + + // Make sure headers are visible + lv.AddTextToRow(null,"","","","","","",null,""); + jobsCompletedView.AddTextToRow(null,"","","","","","",null,""); + jobsReceivedView.AddTextToRow(null,"","","",null,""); + StatusStore.Clear(); + RecvStore.Clear(); + + DeleteJobButton.Sensitive = false; + if (Settings.TransmitAgent == "hylafax") + ModifyJobButton.Sensitive = false; + else + ModifyJobButton.Visible = false; + ViewPrintButton.Sensitive = false; + + // Setup some global variables + gfax.MainProgressBar = Appbar.Progress; + gfax.GStatusTextBuffer = StatusTextBuffer; + gfax.GAppbar = Appbar; + + gfax.Pulser = new Pulser(); + gfax.Status = new Status(StatusText, StatusTextBuffer); + + if (Settings.RefreshQueueEnabled) + GLib.Timeout.Add((uint)(Settings.RefreshQueueInterval * 1000), + new TimeoutHandler (queue_refresh)); + + async_update_status(); + + if (Settings.TransmitAgent == "hylafax" ) { + while (gfax.activeNetwork) + System.Threading.Thread.Sleep(100); + + async_net_read_finished(); + } + + activeQ = ActiveQ.send; + async_update_queue_status("sendq"); + + StatusIcon sicon = new StatusIcon(Icon); + sicon.Activate += new EventHandler (OnImageClick); + sicon.Tooltip = "Gfax Facsimile Sender"; + // showing the trayicon + sicon.Visible = true; + // setup system tray icon + gfax.MainWindow.SkipTaskbarHint = true; + gfax.MainWindow.Iconify(); + + Application.Run (); + } + + // end up here if we click the icon in the notifier + private static void OnImageClick(object o, EventArgs arg) + { + if (iconified) { + gfax.MainWindow.Deiconify(); + iconified = false; + gfax.MainWindow.SkipTaskbarHint = false; + } else { + gfax.MainWindow.Iconify(); + gfax.MainWindow.SkipTaskbarHint = true; + iconified = true; + } + } + + // End up here if we iconify with the window manager + private static void on_mainWindow_window_state_event(object o, WindowStateEventArgs args) + { + //Console.WriteLine ("state event: type=" + args.Event.Type + + // "; new_window_state=" + args.Event.NewWindowState); + + if (args.Event.NewWindowState == Gdk.WindowState.Iconified) { + iconified = true; + gfax.MainWindow.SkipTaskbarHint = true; + } else { + gfax.MainWindow.SkipTaskbarHint = false; + iconified = false; + } + + } + //************************************************************************ + // queue_refresh + // returns true to continue timeout functioning + // + // Queue_refresh connects to the hylafax server and retrieves + // updated queue information on regular intervals. This is called + // from a GLib.TimeoutHandler + public bool queue_refresh () + { + if (!Settings.RefreshQueueEnabled) + return false; + + // always do main status + //update_status(Fax.get_server_status()); + + // TODO do all this stuff with Delegates and events + async_update_status(); + while (gfax.activeNetwork) + System.Threading.Thread.Sleep(100); + // now do queue + + switch (activeQ) { + case ActiveQ.done : + async_update_queue_status("doneq"); + break; + case ActiveQ.send : + async_update_queue_status("sendq"); + break; + case ActiveQ.receive : + async_update_queue_status("recvq"); + break; + } + + return true; // must return true from timeout to keep it active + } + + // Set to true if we need to restart for changed transport agent + public bool Restart + { + get { return restart; } + set { restart = value; } + } + + +//========================= PRIVATE METHODS ==================================== + private void on_StatusList_selection (object o, EventArgs args) + { + if (StatusList.Selection.CountSelectedRows() > 0) { + DeleteJobButton.Sensitive = true; + ModifyJobButton.Sensitive = true; + } else { + DeleteJobButton.Sensitive = false; + ModifyJobButton.Sensitive = false; + } + } + + + private void on_JobsCompleteList_selection (object o, EventArgs args) + { + DeleteJobButton.Sensitive = true; + } + + private void on_JobsReceivedList_selection (object o, EventArgs args) + { + if (JobsReceivedList.Selection.CountSelectedRows() > 0) { + ViewPrintButton.Sensitive = true; + RecvfaxDeleteButton.Sensitive = true; + } else { + ViewPrintButton.Sensitive = false; + RecvfaxDeleteButton.Sensitive = false; + } + } + + // Double click (Send tab) + private void on_StatusList_row_activated (object o, RowActivatedArgs args) + { + modify_job(lv.GetSelections(ALL_COLUMNS), "sendq"); + } + + + private void on_JobsCompleteList_row_activated (object o, RowActivatedArgs args) + { + //modify_job(jobsCompletedView.GetSelections(ALL_COLUMNS), "doneq"); + } + + + private void on_JobsReceivedList_row_activated (object o, RowActivatedArgs args) + { + // get the selected jobs + ArrayList al; + string hfaxfile = null; + + // COLUMN_5 is the filename + al = jobsReceivedView.GetSelections(COLUMN_5); + + IEnumerator enu = al.GetEnumerator(); + while ( enu.MoveNext() ) { + hfaxfile = (string)enu.Current; + } + //Console.WriteLine("File to receive is {0}", hfaxfile); + + view_received_fax( hfaxfile ); + } + + private void on_exitButton_clicked (object o, EventArgs args) + { + Application.Quit(); + } + + private void on_mainWindow_delete_event (object o, DeleteEventArgs args) + { + Application.Quit(); + args.RetVal = true; + } + + private void on_exit1_activate (object o, EventArgs args) + { + Application.Quit(); + restart = true; + } + + +//Status list notebook signal, switch pages to show different queues + private void on_StatusNotebook_switch_page (object o, SwitchPageArgs args) + { + async_update_status(); + while (gfax.activeNetwork) + System.Threading.Thread.Sleep(100); + + switch (StatusNotebook.CurrentPage) { + case SENDQ_PAGE: + activeQ = ActiveQ.send; + //if (update_queue_status("sendq") > 0) + // DeleteJobButton.Sensitive = true; + //else { + DeleteJobButton.Sensitive = false; + //} + async_update_queue_status("sendq"); + break; + case DONEQ_PAGE: + DeleteJobButton.Sensitive = false; + activeQ = ActiveQ.done; + async_update_queue_status("doneq"); + break; + case RECEIVEQ_PAGE: + DeleteJobButton.Sensitive = false; + RecvfaxDeleteButton.Sensitive = false; + activeQ = ActiveQ.receive; + async_update_queue_status("recvq"); + break; + } + + } + +//Main toolbar buttons +//======================================================================= + private void on_NewFaxButton_clicked (object o, EventArgs args) + { + send_new_fax(); + } + + + private void on_PhonebookButton_clicked (object o, EventArgs args) + { + GfaxPhonebook gpb = new GfaxPhonebook(); + } + + + private void on_ModifyJobButton_clicked (object o, EventArgs args) + { + modify_job(lv.GetSelections(ALL_COLUMNS), "sendq"); + } + + private void modify_job (ArrayList al, string id) + { + + string jobid = null; + string number = null; + string status = null; + string user = null; + string pages = null; + string dials = null; + object sendat = null; + string error = null; + + IEnumerator enu = al.GetEnumerator(); + while ( enu.MoveNext() ) { + enu.MoveNext(); + jobid = (string)enu.Current; + enu.MoveNext(); + number = (string)enu.Current; + enu.MoveNext(); + status = (string)enu.Current; + enu.MoveNext(); + user = (string)enu.Current; + enu.MoveNext(); + pages = (string)enu.Current; + enu.MoveNext(); + int idx = ((string)enu.Current).LastIndexOf(':'); + dials = ((string)enu.Current).Substring(idx + 1); + enu.MoveNext(); + sendat = (object)enu.Current; + enu.MoveNext(); + error = (string)enu.Current; + } + + #if DEBUG + Console.WriteLine("[ModifyJob] Date is {0}", sendat); + #endif + + Glade.XML xml = new Glade.XML (null, "gfax.glade","vbox74",null); + Dialog mjd = new Dialog(); + mjd.VBox.Add(xml.GetWidget("vbox74")); + Gtk.Entry mje = (Gtk.Entry)xml.GetWidget("ModifyJobNumberEntry"); + Gnome.DateEdit mjde = (Gnome.DateEdit)xml.GetWidget("ModifyJobDate"); + Gtk.SpinButton mjmd = (Gtk.SpinButton)xml.GetWidget("MaxDialsSpinbutton"); + + mjd.AddButton (Gtk.Stock.Cancel, Gtk.ResponseType.Cancel); + mjd.AddButton (Gtk.Stock.Ok, Gtk.ResponseType.Ok); + + // this is to re-enable the entry for editing so it won't be selected + // to begin with??? Maybe something to do with re-parenting or something. + mje.FocusInEvent += + new FocusInEventHandler (on_ModifyJobNumberEntry_focus_in_event); + + mje.IsEditable = false; + mje.Text = number.Trim(); + + mjde.Time = sendat == null ? new DateTime(): (DateTime)sendat; + + mjmd.Value = Convert.ToDouble(dials.Trim()); + + ResponseType result = (ResponseType)mjd.Run (); + + if (result == ResponseType.Ok) { + DateTime newsend = (mjde.Time).ToUniversalTime(); + + // Format time to send - timezone is in UTC format. + string tts = String.Format("{0}{1:00}{2:00}{3:00}{4:00}", + newsend.Year, + newsend.Month, + newsend.Day, + newsend.Hour, + newsend.Minute); + + if (id == "sendq" ) + Fax.modify_job(jobid, mje.Text, tts, (mjmd.ValueAsInt).ToString()); + else // "doneq" + Fax.resubmit_job(jobid, mje.Text, tts, (mjmd.ValueAsInt).ToString()); + + mjd.Destroy(); + } else { + mjd.Destroy(); + } + + async_update_queue_status("sendq"); + ModifyJobButton.Sensitive = false; + DeleteJobButton.Sensitive = false; + } + + public void on_ModifyJobNumberEntry_focus_in_event (object o, EventArgs args) + { + Gtk.Entry e = o as Gtk.Entry; + e.IsEditable = true; + } + + private void on_DeleteJobButton_clicked (object o, EventArgs args) + { + // get the selected jobs + ArrayList al; + + // get a list of jobids to kill + al = lv.GetSelections(COLUMN_1); + + IEnumerator enu = al.GetEnumerator(); + while ( enu.MoveNext() ) { + Fax.delete_job((string)enu.Current); + } + + switch (activeQ) { + case ActiveQ.done : + async_update_queue_status("doneq"); + break; + case ActiveQ.send : + async_update_queue_status("sendq"); + break; + case ActiveQ.receive : + async_update_queue_status("recvq"); + break; + } + + DeleteJobButton.Sensitive = false; + ModifyJobButton.Sensitive = false; + } + + private void on_ViewPrintButton_clicked (object o, EventArgs args) + { + // get the selected jobs + ArrayList al; + string hfaxfile = null; + + // COLUMN_5 is the filename + al = jobsReceivedView.GetSelections(COLUMN_5); + + IEnumerator enu = al.GetEnumerator(); + while ( enu.MoveNext() ) { + hfaxfile = (string)enu.Current; + } + + view_received_fax (hfaxfile); + } + + private void view_received_fax (string s) + { + // TODO get proper Gnome mime type and use that first if running Gnome + try { + if (Fax.recvfax(s)) { + ProcessStartInfo pidInfo = new ProcessStartInfo(); + pidInfo.FileName = Settings.FaxViewer; + pidInfo.Arguments = String.Concat(gfax.SpoolDirectory, "/tif/", s); + System.Diagnostics.Process pid = System.Diagnostics.Process.Start(pidInfo); + } else { + G_Message gm = new G_Message(Catalog.GetString( +@"Cannot read the facsimile file from the server. You most likely do not +have permission to read the file. Check the settings on your fax server." )); + return; + } + + } catch (Exception e) { + G_Message gm = new G_Message(Catalog.GetString( +@"Cannot start your faxviewer program. +Please check your settings. It is currently set to " + Settings.FaxViewer + "." )); + } + + switch (activeQ) { + case ActiveQ.done : + async_update_queue_status("doneq"); + break; + case ActiveQ.send : + async_update_queue_status("sendq"); + break; + case ActiveQ.receive : + async_update_queue_status("recvq"); + break; + } + + // Reset progressbar + gfax.MainProgressBar.Fraction = 0; + } + + private void on_RecvfaxDeleteButton_clicked (object o, EventArgs args) + { + // get the selected jobs + ArrayList al; + string hfaxfile = null; + + // COLUMN_5 is the filename + al = jobsReceivedView.GetSelections(COLUMN_5); + + IEnumerator enu = al.GetEnumerator(); + while ( enu.MoveNext() ) { + hfaxfile = (string)enu.Current; + + try { + if (Fax.delete_file(hfaxfile) == 1) { + G_Message gm = new G_Message(Catalog.GetString( +@"Cannot delete the facsimile file from the server. You most likely do not +have permission to delete the file. Check the settings on your fax server." )); + return; + } + } catch (Exception e) { + G_Message gm = new G_Message(Catalog.GetString( +@"Cannot delete the file on the Hylafax server. +Please check your settings or contact your system Administrator")); + } + + switch (activeQ) { + case ActiveQ.done : + async_update_queue_status("doneq"); + break; + case ActiveQ.send : + async_update_queue_status("sendq"); + break; + case ActiveQ.receive : + async_update_queue_status("recvq"); + break; + } + } + } + + + +// Menu items selected ============================================= + private void on_newfax_activate (object o, EventArgs args) + { + send_new_fax(); + } + + private void on_preferences_activate (object o, EventArgs args) + { + GfaxPrefs gp = new GfaxPrefs(); + } + + private void on_jobs1_activate (object o, EventArgs args) + { + + } + + private void on_auto_queue_refresh_check_menu_item_activate (object o, EventArgs args) + { + if (eventsEnabled) { + Settings.RefreshQueueEnabled = !Settings.RefreshQueueEnabled; + if (Settings.RefreshQueueEnabled) + GLib.Timeout.Add((uint)(Settings.RefreshQueueInterval * 1000), + new TimeoutHandler(queue_refresh)); + } + } + + private void on_log_enabled_check_menu_item_activate (object o, EventArgs args) + { + if (eventsEnabled) + Settings.LogEnabled = !Settings.LogEnabled; + } + + private void on_email_notification_check_menu_item_activate (object o, EventArgs args) + { + if (eventsEnabled) + Settings.EmailNotify = !Settings.EmailNotify; + } + + private void on_hi_resolution_mode_check_menu_item_activate (object o, EventArgs args) + { + if (eventsEnabled) + Settings.HiResolution = !Settings.HiResolution; + } + + private void on_fax_tracing_check_menuItem_activate (object o, EventArgs args) + { + if (eventsEnabled) + Settings.Faxtracing = !Settings.Faxtracing; + } + + + private static AboutDialog about = null; + private static void on_about_activate (object sender, EventArgs args) + { + if (about == null) + about = new AboutDialog(); + + about.Name = NAME; + about.Version = VERSION; + about.LogoIconName = "gfax"; + about.Authors = new string[] { "George Farris <farrisg@shaw.ca>" }; + about.Documenters = new string[] {}; + about.Copyright = Catalog.GetString("Copyright (C) 2003 George Farris <farrisg@shaw.ca>"); + about.Comments = Catalog.GetString("A Facsimile application for GNOME"); + about.TranslatorCredits = ( + "Johannes Rohr <johannes@rohr.org> - German\n" + + "Maris Dembovskis <marisdembovskis@gmail.com> - Latvian\n" + + "Sasa Ostrouska <saxa@droplinegnome.org> Italian\n" + + "Bart Verstraete <bartverstraete@telenet.be> - Dutch"); + about.Run(); + about.Hide(); + } + + +//--------------------------- SUPPORT FUNCTIONS ------------------------------- + Gdk.Pixbuf fax_fail; + Gdk.Pixbuf fax_sent; + Gdk.Pixbuf fax_sleep; + Gdk.Pixbuf fax_block; + Gdk.Pixbuf fax_run; + Gdk.Pixbuf fax_receiving; + Gdk.Pixbuf fax_received; + + public void InitListViewIcons() + { + fax_receiving = Gtk.IconTheme.Default.LoadIcon ("document-save", 16, 0); + fax_fail = Gtk.IconTheme.Default.LoadIcon ("gtk-cancel", 16, 0); + fax_sent = Gtk.IconTheme.Default.LoadIcon ("gtk-apply", 16, 0); + fax_run = Gtk.IconTheme.Default.LoadIcon ("printer-printing", 16, 0); + fax_block = Gtk.IconTheme.Default.LoadIcon ("printer-error", 16, 0); + fax_sleep = Gtk.IconTheme.Default.LoadIcon ("appointment-soon", 16, 0); + fax_received = Gtk.IconTheme.Default.LoadIcon ("text-x-generic", 16, 0); + } + + public Gdk.Pixbuf GetFaxStatusIcon (FaxStatus status) + { + switch (status) + { + case FaxStatus.Fail: + return fax_fail; + case FaxStatus.New: + return fax_run; + case FaxStatus.Busy: + return fax_block; + case FaxStatus.Block: + return fax_block; + case FaxStatus.Sleep: + return fax_sleep; + case FaxStatus.Run: + return fax_run; + case FaxStatus.Receiving: + return fax_receiving; + case FaxStatus.Received: + return fax_received; + } + + return fax_sent; + } + + // Updates the status text widget + // only used for Efax + public void update_status (string s) + { + if (s == null) + return; + + if (Settings.TransmitAgent == "efax") { + TextMark tm = StatusTextBuffer.GetMark("insert"); + StatusTextBuffer.InsertAtCursor(String.Concat(s, "\n")); + StatusText.ScrollMarkOnscreen(tm); + } + } + + public void async_update_status () + { + string s; + + if (Settings.TransmitAgent == "efax") { + s = Fax.async_get_server_status(); + if (s != null ) { + TextMark tm = StatusTextBuffer.GetMark("insert"); + StatusTextBuffer.InsertAtCursor(String.Concat(s, "\n")); + StatusText.ScrollMarkOnscreen(tm); + } + } + + if (Settings.TransmitAgent == "hylafax") { + // Progressbar pulser - add this when we have async comms + GLib.Timeout.Add((uint)(100), new TimeoutHandler (queue_progress)); + + // update status bar + Appbar.ClearStack(); + Appbar.Push(Catalog.GetString("Refreshing server status...")); + Appbar.Refresh(); + //GLib.MainContext.Iteration (); + while (Gtk.Application.EventsPending ()) + Gtk.Application.RunIteration (); + + s = Fax.async_get_server_status(); + } + } + + + private void async_update_queue_status(string queue) + { + G_ListView view; + Fax.FaxQueue q = null; + Fax.FaxRecQueue rq = null; + + view = lv; + + switch (queue) { + case "sendq": + view = lv; + break; + case "doneq": + view = jobsCompletedView; + break; + case "recvq": + view = jobsReceivedView; + break; + } + + if (Settings.TransmitAgent == "hylafax") { + // Progressbar pulser - add this when we have async comms + GLib.Timeout.Add((uint)(100), new TimeoutHandler (queue_progress)); + + // update status bar + Appbar.ClearStack(); + Appbar.Push(Catalog.GetString("Refreshing queue...")); + Appbar.Refresh(); + //GLib.MainContext.Iteration (); + while (Gtk.Application.EventsPending ()) + Gtk.Application.RunIteration (); + + Fax.async_get_queue_status(queue); + } + if (Settings.TransmitAgent == "efax") { + async_update_listview(Fax.async_get_queue_status(queue), queue); + } + } + + // We end up here when an async network read is finished + private void async_net_read_finished () + { + switch (gfax.asyncReadType) { + case "doneq" : + async_update_listview(Fax.parse_senddone(gfax.asyncFolderMessageBuffer), "doneq"); + break; + case "sendq" : + async_update_listview(Fax.parse_senddone(gfax.asyncFolderMessageBuffer), "sendq"); + break; + case "recvq" : + async_update_listview(Fax.parse_receive(gfax.asyncFolderMessageBuffer), "recvq"); + break; + case "status" : + StatusTextBuffer.Text = gfax.asyncServerMessageBuffer; + break; + } + } + + private void async_update_listview(ArrayList reply, string queue) + { + G_ListView view; + Fax.FaxQueue q = null; + Fax.FaxRecQueue rq = null; + + view = lv; + + switch (queue) { + case "sendq": + view = lv; + break; + case "doneq": + view = jobsCompletedView; + break; + case "recvq": + view = jobsReceivedView; + break; + } + + if (reply.Count > 0) { + StatusStore.Clear(); + RecvStore.Clear(); + IEnumerator enu = reply.GetEnumerator(); + + if (queue == "sendq" || queue == "doneq") { + while ( enu.MoveNext() ) { + q = (Fax.FaxQueue)enu.Current; + view.AddTextToRow(GetFaxStatusIcon(q.StatusType), q.Jobid, q.Number, q.Status, q.Owner, q.Pages, q.Dials, q.Sendat, q.Error); + } + + Appbar.ClearStack(); + + if (q.Jobid != "") { + Appbar.Push(Catalog.GetString("There are " + reply.Count + " jobs in the queue")); + Appbar.Refresh(); + //((Gtk.Window) gxml["Gfax"]).Title = "Gfax (" + reply.Count + ")"; + GfaxWindow.Title = "Gfax (" + reply.Count + ")"; + //return reply.Count; + return; + } else { + Appbar.Push(Catalog.GetString("There are 0 jobs in the queue")); + Appbar.Refresh(); + //((Gtk.Window) gxml["Gfax"]).Title = "Gfax"; + GfaxWindow.Title = "Gfax"; + } + } else { //receive queue + while ( enu.MoveNext() ) { + rq = (Fax.FaxRecQueue)enu.Current; + view.AddTextToRow(GetFaxStatusIcon(rq.StatusType), rq.Sender, rq.Status, rq.Pages, rq.TimeReceived, rq.Filename); + } + + if (rq.Sender != "") { + Appbar.Push(Catalog.GetString("There are " + reply.Count + " jobs in the queue")); + Appbar.Refresh(); + //((Gtk.Window) gxml["Gfax"]).Title = "Gfax (" + reply.Count + ")"; + GfaxWindow.Title = "Gfax (" + reply.Count + ")"; + //return reply.Count; + return; + } else { + Appbar.Push(Catalog.GetString("There are 0 jobs in the queue")); + Appbar.Refresh(); + //((Gtk.Window) gxml["Gfax"]).Title = "Gfax"; + GfaxWindow.Title = "Gfax"; + } + } + + oldSendQueue = reply; // else save queue + } + + + StatusStore.Clear(); + RecvStore.Clear(); + } + + + private bool queue_progress () + { + if (gfax.activeNetwork) { + Appbar.Progress.Pulse(); + return (true); + } + else { + async_net_read_finished(); + Appbar.Progress.Fraction = 0; + return (false); + } + } + + // This is where we end up if the New Fax button or the menu item + // has been selected. + private void send_new_fax () + { + + string [] largs = {"do_filename"}; + GfaxSend sd = new GfaxSend ("", largs); + + // send the faxes + if (sd.DoSend) { + Fax.sendfax(sd.Filename); + // if file is temp data (/var/spool/gfax/D.*) then delete it + FileInfo f = new FileInfo(sd.Filename); + if (File.Exists(String.Concat(gfax.SpoolDirectory, "/", f.Name))) + File.Delete(String.Concat(gfax.SpoolDirectory, "/", f.Name)); + } + activeQ = ActiveQ.send; + async_update_queue_status("sendq"); + sd = null; + largs = null; + } + + } + + public class Status + { + TextBuffer stb; + TextView stv; + + public Status (Gtk.TextView StatusText, TextBuffer StatusTextBuffer) + { + stv = StatusText; + stb = StatusTextBuffer; + } + + public void Append (string s) + { + TextMark tm = stb.GetMark("insert"); + stb.InsertAtCursor(String.Concat(s, "\n")); + stv.ScrollMarkOnscreen(tm); + } + } + + // pulse the main window progressbar + public class Pulser + { + public bool endPulse; + + public void StartPulse () + { + endPulse = true; + GLib.Timeout.Add((uint)(200), + new TimeoutHandler (PulseIt)); + } + + public void EndPulse () + { + endPulse = false; + } + + private bool PulseIt () + { + gfax.MainProgressBar.Pulse(); + if (endPulse) + return(true); + else { + gfax.MainProgressBar.Fraction = 0; + return(false); + } + } + } + +} diff --git a/src/guitools.cs b/src/guitools.cs new file mode 100755 index 0000000..8828941 --- /dev/null +++ b/src/guitools.cs @@ -0,0 +1,540 @@ +// GFAX - Gnome fax application +// Copyright (C) 2003 - 2008 George A. Farris +// +// 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 3 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 Library 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. + +namespace gfax { + using System; + using System.IO; + using System.Collections; + using System.Reflection; + using GLib; + using Gtk; + using Gdk; + using Gnome; + using Glade; + using GtkSharp; + + // G_ProgressBar + public class G_ProgressBar + { + [Glade.Widget] Gtk.Dialog HylafaxProgressDialog; + [Glade.Widget] ProgressBar HylafaxProgressbar; + [Glade.Widget] Gtk.Notebook HylafaxProgressNotebook; + [Glade.Widget] Gtk.Button HylafaxProgressCancelButton; + [Glade.Widget] Gtk.Button HylafaxProgressCloseButton; + + bool close = true; + bool cancel = false; // Cancel all jobs + + public G_ProgressBar () + { + Glade.XML xml = new Glade.XML (null, "gfax.glade","HylafaxProgressDialog",null); + xml.Autoconnect (this); + + HylafaxProgressNotebook.CurrentPage = 0; + HylafaxProgressCloseButton.Hide(); + HylafaxProgressDialog.Show(); + } + + public bool Cancel + { + get { return cancel; } + } + + private void on_HylafaxProgressCancelButton_clicked(object o, EventArgs args) + { + cancel = true; + } + + private void on_HylafaxProgressCloseButton_clicked(object o, EventArgs args) + { + close = false; + HylafaxProgressDialog.Destroy(); + } + + public void Close() + { + //close = false; + //HylafaxProgressDialog.Hide(); + //HylafaxProgressDialog.Dispose(); + HylafaxProgressDialog.Destroy(); + } + + //public void Run () + //{ + // HylafaxProgressDialog.Run(); + //} + + public double Fraction + { + set { HylafaxProgressbar.Fraction = value; } + } + + public void Finished() + { + HylafaxProgressNotebook.CurrentPage = 1; + HylafaxProgressCancelButton.Hide(); + HylafaxProgressCloseButton.Show(); + // TODO Bad, bad, slap your wrist boy, do timer function + // or fix this somehow. Can I say 100% processor useage. + //while (close) { + // while (Gtk.Application.EventsPending ()) + // Gtk.Application.RunIteration (); + //} + } + } + + // G_Message class + // + // A simple message dialog + public class G_Message + { + public G_Message (string s) + { + MessageDialog d = new MessageDialog ( + null, DialogFlags.DestroyWithParent, MessageType.Error, ButtonsType.Ok, s); + d.Run (); + d.Destroy (); + } + + public G_Message (string s, bool toplevel) + { + Application.Init(); + MessageDialog d = new MessageDialog ( + null, DialogFlags.DestroyWithParent, MessageType.Error, ButtonsType.Ok, s); + d.Run (); + d.Destroy (); + Application.Quit(); + } + } + + public class G_Password + { + [Glade.Widget] Gtk.Dialog PasswordDialog; + [Glade.Widget] Gtk.Entry PasswordEntry; + + string pass; // the password entered + bool cancel = false; // Cancel the connection + bool remember = false; // Remember the password + + public G_Password () + { + Glade.XML xml = new Glade.XML (null, "gfax.glade","PasswordDialog",null); + xml.Autoconnect (this); + + PasswordDialog.Show(); + } + + public bool Cancel + { + get { return cancel; } + } + + public bool RememberPassword + { + get { return remember; } + } + + public string Password + { + get { return pass; } + } + + public void Run () + { + PasswordDialog.Run(); + } + + private void on_PasswordCheckbutton_toggled(object o, EventArgs args) + { + remember = true; + } + + private void on_cancelbutton_clicked(object o, EventArgs args) + { + cancel = true; + PasswordDialog.Hide(); + } + + private void on_PasswordEntry_activate(object o, EventArgs args) + { + pass = PasswordEntry.Text; + PasswordDialog.Hide(); + } + + private void on_okbutton_clicked(object o, EventArgs args) + { + pass = PasswordEntry.Text; + PasswordDialog.Hide(); + } + + public void Close() + { + PasswordDialog.Destroy(); + } + } + + + // *********************************************************************** + // + // G_GetFilename class + // + // Implements a GTK+ fileselector with signal handler for Ok and Cancel + // Arguments: + // string title : Title open file selection dialog + // string dir : Starting directory + + public class G_GetFilename + { + string fname; + public Gtk.FileSelection fs; + + public G_GetFilename (string title, string dir) + { + fs = new FileSelection(title); + fs.Filename = dir; + fs.Modal = true; + fs.HideFileopButtons (); + fs.OkButton.Clicked += new EventHandler (ok); + fs.CancelButton.Clicked += new EventHandler (cancel); + +/* + check_button = new CheckButton ("Show Fileops"); + check_button.Toggled += new EventHandler (show_fileops); + fs.ActionArea.PackStart (check_button, false, false, 0); + + toggle_button = new ToggleButton ("Select Multiple"); + toggle_button.Clicked += new EventHandler (select_multiple); + fs.ActionArea.PackStart (toggle_button, false, false, 0); +*/ + fs.ShowAll(); + fs.Run (); + } + + public void Destroy () + { + fs.Destroy(); + } + + private void cancel (object o, EventArgs args) + { + //Console.WriteLine("[Cancel] file selection cancel"); + fs.Hide (); + } + + private void ok (object o, EventArgs args) + { + //Console.WriteLine(fs.Filename); + fname = fs.Filename; + fs.Hide (); + } + + public string Fname + { + get {return fname;} + set {fname = value;} + } + + + } + + public class CellRendererDateTime: CellRendererText + { + public string Format; + } + + public class G_ListView + { + Gtk.ListStore store; + Gtk.TreeView tree; + Gtk.TreeViewColumn column; + Gtk.CellRendererText textrenderer; + CellRendererDateTime datetimerenderer; + Gtk.CellRendererPixbuf iconrenderer; + Gtk.TreeIter iter; + Value valnot = new Value(false); + Value valone = new Value(true); + + const int COLUMN_0 = 0; + const int COLUMN_1 = 1; + const int COLUMN_2 = 2; + const int ALL_COLUMNS = -1; + + public G_ListView (Gtk.TreeView tr, Gtk.ListStore st) + { + store = st; + tree = tr; + iter = new Gtk.TreeIter(); + } + + public void AddColumnIcon (string iconname, int col) + { + column = new TreeViewColumn (); + iconrenderer = new Gtk.CellRendererPixbuf (); + column.Expand = false; + column.Resizable = false; + column.Clickable = false; + column.Reorderable = false; + column.Alignment = 0.5f; + column.Widget = new Gtk.Image( + Gtk.IconTheme.Default.LoadIcon (iconname, 16, 0) + ); + column.Widget.Show(); + column.PackStart (iconrenderer, true); + column.AddAttribute (iconrenderer, "pixbuf", col); + tree.AppendColumn(column); + } + + protected int DateTimeTreeIterCompareFunc (TreeModel model, TreeIter a, TreeIter b) + { + int col = -1; + SortType sort; + + bool is_sorted = ((Gtk.ListStore)model).GetSortColumnId (out col, out sort); + if(!is_sorted) + return 0; + + DateTime dateA = (DateTime)model.GetValue (a, col); + DateTime dateB = (DateTime)model.GetValue (b, col); + + return dateA.CompareTo(dateB); + } + + protected void DateTimeColumnDataHandler (TreeViewColumn column, + CellRenderer cell, TreeModel model, TreeIter iter) + { + DateTime date = (DateTime)model.GetValue (iter, column.SortColumnId); + CellRendererDateTime renderer = (CellRendererDateTime)cell; + renderer.Text = date.ToString(renderer.Format); + } + + public void AddColumnDateTime (string title, string format, int sortid, int col) + { + store.SetSortFunc(col, new TreeIterCompareFunc(DateTimeTreeIterCompareFunc)); + + column = new TreeViewColumn (); + datetimerenderer = new CellRendererDateTime (); + datetimerenderer.Format = format == null ? "G" : format; + column.Title = title; + column.SortColumnId = sortid; + column.Sizing = TreeViewColumnSizing.Autosize; + column.Reorderable = true; + column.Resizable = true; + column.Expand = false; + column.Alignment = 0.0f; + column.PackStart (datetimerenderer, true); + column.SetCellDataFunc (datetimerenderer, new TreeCellDataFunc(DateTimeColumnDataHandler)); + tree.AppendColumn(column); + } + + public void AddColumnTitle (string title, int sortid, int col) + { + column = new TreeViewColumn (); + textrenderer = new CellRendererText (); + //text.Editable = true;object + column.Title = title; + column.SortColumnId = sortid; + column.Sizing = TreeViewColumnSizing.Autosize; + column.Reorderable = true; + column.Resizable = true; + column.Expand = false; + column.Alignment = 0.0f; + column.PackStart (textrenderer, true); + column.AddAttribute (textrenderer, "text", col); + tree.AppendColumn(column); + } + +// TODO move this to GfaxSend in gui.cs + public void AddColumnTitleToggle (string title, int sortid, int col) + { + column = new TreeViewColumn (); + CellRendererToggle toggle = new CellRendererToggle (); + toggle.Activatable = true; + toggle.Toggled += new ToggledHandler (toggle_it); + column.Title = title; + column.PackStart (toggle, false); + column.AddAttribute (toggle, "active", col); + tree.AppendColumn(column); + } + + // we need to manually set the toggle when selected otherwise + // it won't show in the gui. + public void toggle_it (object o, Gtk.ToggledArgs args) + { + store.GetIterFromString(out iter, args.Path); + bool tog = (bool)store.GetValue(iter, 0); + store.SetValue(iter, 0, !tog); + } +// end of move + + // Each arg is a new column + public void AddTextToRow (params object[] args) + { + iter = store.AppendValues(args); + tree.Model = store; + } + + // returns a list of arrays of columns size + public ArrayList GetAllRows() + { + ArrayList rows = new ArrayList(); + + // Really get the whole row. + string[] col = new string[store.NColumns]; + store.GetIterFirst(out iter); + + for ( int i = 0; i < store.NColumns; i++) { + try { + col[i] = (string)store.GetValue(iter, i); + //Console.WriteLine("Column {0}",col[i]); + } + catch (Exception e) { } + } + rows.Add(col); + + #if DEBUG + Console.WriteLine("got colums"); + #endif + + while (store.IterNext(ref iter)) { + string[] coln = new string[store.NColumns]; + for ( int i = 0; i < store.NColumns; i++) { + coln[i] = (string)store.GetValue(iter, i); + } + rows.Add(coln); + } + return rows; + } + + // get multiple selections, return a list of objects + public ArrayList GetSelections(int column) + { + ArrayList selects = new ArrayList(); + + // Really get the whole row. + if (column == ALL_COLUMNS) { + store.GetIterFirst(out iter); + if ( tree.Selection.IterIsSelected(iter)) { + for ( int i = 0; i < store.NColumns; i++) { + selects.Add(store.GetValue(iter, i)); + } + } + + while (store.IterNext(ref iter)) { + if ( tree.Selection.IterIsSelected(iter)) { + for ( int i = 0; i < store.NColumns; i++) { + selects.Add(store.GetValue(iter, i)); + } + } + } + } + else + { + store.GetIterFirst(out iter); + if ( tree.Selection.IterIsSelected(iter)) { + selects.Add(store.GetValue(iter, column)); + } + + while (store.IterNext(ref iter)) { + if ( tree.Selection.IterIsSelected(iter)) { + selects.Add(store.GetValue(iter, column)); + } + } + } + return selects; + } + + // get single selection + public object GetSingleSelection () + { + object sel = null; + Gtk.TreeIter iter = new Gtk.TreeIter(); + + store.GetIterFirst(out iter); + if ( tree.Selection.IterIsSelected(iter)) { + sel = store.GetValue(iter, 0); + } + + while (store.IterNext(ref iter)) { + if ( tree.Selection.IterIsSelected(iter)) { + sel = store.GetValue(iter, 0); + } + } + return sel; + } + + public void RemoveSelectedRow () + { + Gtk.TreeIter iter = new Gtk.TreeIter(); + + store.GetIterFirst(out iter); + if ( tree.Selection.IterIsSelected(iter)) { + store.Remove(ref iter); + return; + } + + while (store.IterNext(ref iter)) { + if ( tree.Selection.IterIsSelected(iter)) { + store.Remove(ref iter); + break; + } + } + return; + } + + //TODO get this to work + public void RemoveSelectedRows () + { + Gtk.TreeIter iter = new Gtk.TreeIter(); + + store.GetIterFirst(out iter); + if ( tree.Selection.IterIsSelected(iter)) { + store.Remove(ref iter); + } + + while (store.IterNext(ref iter)) { + if ( tree.Selection.IterIsSelected(iter)) { + store.Remove(ref iter); + } + } + return; + } + + + public void UpdateColumnText (string oldString, string newString, int column) + { + Gtk.TreeIter iter = new Gtk.TreeIter(); + + store.GetIterFirst(out iter); + // Check for a null Stamp (no initial entry in the list) + if (iter.Stamp == 0) + return; + + if ( oldString == (string)store.GetValue(iter, column)) { + GLib.Value val = new GLib.Value(newString); + store.SetValue (iter, column, val); + } + + while (store.IterNext(ref iter)) { + if ( oldString == (string)store.GetValue(iter, column)) { + GLib.Value val1 = new GLib.Value(newString); + store.SetValue (iter, column, val1); + } + } + + } + } +} diff --git a/src/hylafax.cs b/src/hylafax.cs new file mode 100755 index 0000000..54ab63f --- /dev/null +++ b/src/hylafax.cs @@ -0,0 +1,950 @@ +// GFAX - Gnome fax application +// Copyright (C) 2003 - 2008 George A. Farris +// +// 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 3 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 Library 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. + + // Sequence to send a file is: + // 1) Make sure we're connected + // 2) Store the filename on the server [storefile_open] + // 3) Send the file line by line + // 4) Close the stream for sending the file + // 5) For all the phone numbers do: + // a) job_new [job_new] + // b) set all job parms [job_parm_set] + // c) submit the job [submit_job] + // 6) Close the connection. + +// Properties +// string Hostname, Username, Password +// int IPPort + +//#define DEBUGHYLAFAX + +namespace gfax { + using Mono.Unix; + using System; + using System.IO; + using System.Text; //Encoding.ASCII.GetBytes + using System.Collections; + using System.Threading; + using System.Net; + using System.Net.Sockets; + + + public class Hylafax + { + TcpClient mainclient = new TcpClient(); + NetworkStream mainstream; + string host, user, pass; + int port; + bool permission; + + + public class StateObject + { + public TcpClient client = null; + public int totalBytesRead = 0; + public const int BufferSize = 256; + public string readType = null; + public byte[] buffer = new byte[BufferSize]; + public StringBuilder messageBuffer = new StringBuilder(); + } + + + // connect + // return false on sucess or true on cancel + public bool connect () + { + host = Settings.Hostname; + port = Convert.ToInt32(Settings.Port); + user = Settings.Username; + if (gfax.hylafaxPassword == null) // if we already entered a pass but + if (Settings.Password != "") // don't want to remember it it won't be null + gfax.hylafaxPassword = Settings.Password; + + if (Settings.Faxtracing == true) { + Console.WriteLine ("Initializing hylafax class ......."); + } + + try { + mainclient.Connect(host, port); + mainstream = mainclient.GetStream(); + string s = read(mainstream, mainclient); + if (Settings.Faxtracing == true) { + Console.WriteLine ("[hylafax.connect] on connect : {0}", s); + } + + + if(mainstream.CanWrite && mainstream.CanRead){ + // Write username + if (Settings.Faxtracing == true) { + Console.WriteLine ("[hylafax.connect] Sending USER : {0}", user); + } + + //If the username is null then hylafax doesn't need usernames + // TODO check the hylafax protocol about this + if (user == "") + user = "anonymous"; + + write (mainstream, "USER " + user + "\n"); + // Read result + // If the result is ("230 User <username> logged in.") + // I don't need to send a password + // Else if the result is ("331 Password required for <username>.") + // I must send a password. + string returndata = read(mainstream, mainclient); + + if (returndata.Substring(0,3) == "331") { + //Console.WriteLine("Password is {0}", gfax.hylafaxPassword); + for (int i = 0; i < 3; i++) { + + if (gfax.hylafaxPassword == null) { + G_Password gpass = new G_Password(); + gpass.Run(); + + if (gpass.Cancel) { + return false; // connection cancelled + } + gfax.hylafaxPassword = gpass.Password; + if (gpass.RememberPassword) + Settings.Password = gpass.Password; + gpass.Close(); + } + // 530 Login incorrect. result from bad password + //prompt for password + write (mainstream, "PASS " + gfax.hylafaxPassword + "\n"); + + string rtn = read(mainstream, mainclient); + //Console.WriteLine("Return is {0}", rtn); + if (rtn.Substring(0,3) == "230") // user is logged in + break; + else { + gfax.hylafaxPassword = null; + write (mainstream, "USER " + user + "\n"); + string rtndata = read(mainstream, mainclient); + } + } + } + + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.connect] USER returned : {0}", returndata); + } + } + else if (!mainstream.CanRead) { + Console.WriteLine(Catalog.GetString("You can not write data to this stream")); + mainclient.Close(); + } + else if (!mainstream.CanWrite) { + Console.WriteLine(Catalog.GetString("You can not read data from this stream")); + mainclient.Close(); + } + + return true; + } + catch (Exception e ) { + Console.WriteLine(e.ToString()); + G_Message m = new G_Message(Catalog.GetString("Could not connect to your Hylafax server.\n" + + "Check console messages for further information\n\n" + + "You might need to set a value for username.")); + return false; + } + } + + public void close () + { + mainclient.Close(); + } + + // Method status(queue) + // + // queue is the queue directory of the hylafax server it can be one of: + // 'status', 'sendq', 'doneq' or 'recvq' + // + // Return a list containing lines +/* + public string status (string queue) + { + #if DEBUGHYLAFAX + Console.WriteLine ("[hylafax.status] queue is : {0}", queue); + #endif + // try + return getfolder(queue); + } +*/ + public void asyncstatus (string queue) + { + if (Settings.Faxtracing == true) { + Console.WriteLine ("[hylafax.status] queue is : {0}", queue); + } + asyncgetfolder(queue); + } + + // send_init (string filename) + // + // 2) Store the filename on the server [storefile_open] + // 3) Send the file line by line + // 4) Close the stream for sending the file + public string send_init (string fname) + { + G_ProgressBar pbar; + TcpClient myclient; + NetworkStream mystream; + StreamReader fp = null; + string buf; + string remote_fname; + double lines = 0; + double lines_sent = 0; + double percent = 0; + + if (Settings.Faxtracing == true) { + Console.WriteLine("[Hylafax.send_init] Filename : {0}", fname); + } + + //timezone("LOCAL"); + // Setup the server and return a passive connection + // PASV, STOT + myclient = storefile_open(); + if (Settings.Faxtracing == true) { + Console.WriteLine("[Hylafax.send_init] Got tcpclient"); + } + + mystream = myclient.GetStream(); + if (Settings.Faxtracing == true) { + Console.WriteLine("[Hylafax.send_init] Stream is open"); + } + //figure out how many lines in the file for progress bar + // TODO progress bar and error + try { fp = File.OpenText(fname); } + catch (Exception e) { } + + while ( (buf = fp.ReadLine()) != null ) { + lines = lines + 1; + } + fp.Close(); + + try { fp = File.OpenText(fname); } + catch (Exception e) { } + + if (Settings.Faxtracing == true) { + Console.WriteLine("[Hylafax.send_init] File :{0} is open and has {1} lines", fname,lines); + } + + pbar = new G_ProgressBar(); + //pbar.Text = "File xmit"; + lines_sent = 1; + while ( (buf = fp.ReadLine()) != null ) { + write(mystream, buf); + write(mystream, "\n"); + lines_sent = lines_sent + 1; + percent = lines_sent / lines; + if (percent <= 1.0) + pbar.Fraction = percent; + //GLib.MainContext.Iteration (); + while (Gtk.Application.EventsPending ()) + Gtk.Application.RunIteration (); + if (pbar.Cancel) + break; + } + fp.Close(); + remote_fname = storefile_close(myclient); + + if (pbar.Cancel) { //If the transfer was cancelled + deletefile(remote_fname); + remote_fname = "cancelled"; + pbar.Close(); + } else { + pbar.Finished(); + } + + if (Settings.Faxtracing == true) { + Console.WriteLine("[Hylafax.send_init] Stream is closed, sent {0} lines",lines_sent); + } + return remote_fname; + } + + // Method send(string filename_on_server, Contact contact) + // + // Sequence to send a file is: + // a) job_new [job_new] + // b) set all job parms [job_parm_set] + // c) submit the job [submit_job] + // format send time - should be as such: + // yyyymmddhhmm + //-> JPARM SENDTIME 200403100509 + //213 SENDTIME set to 20040310050900. + public void send (string remote_fname, GfaxContact contact) + { + if (Settings.Faxtracing == true) { + Console.WriteLine("Hylafax.send] top of method..."); + } + + string emailAddress = Settings.EmailAddress; + if (Settings.Faxtracing == true) { + Console.WriteLine("Hylafax.send] email address {0}", emailAddress); + } + + string resolution = "98"; + string emailNotify = "none"; + + if (Settings.Faxtracing == true) { + Console.WriteLine("[Hylafax.send] gfax.timeToSend : {0}", gfax.timeToSend); + Console.WriteLine("[Hylafax.send] Remote file name is : {0}", remote_fname); + } + + // if this is sent from GfaxSend wizard + if (gfax.fromSendWizard) { + if (gfax.sendWizardResolution) + resolution = "196"; + + if (gfax.sendWizardEmailNotify) { + emailNotify = "done"; + emailAddress = gfax.sendWizardEmailAddress; + } + } else { + if (Settings.EmailNotify) + emailNotify = "done"; + + if (Settings.HiResolution) + resolution = "196"; + } + + // Format time to send - timezone is in UTC format. + string tts = String.Format("{0}{1:00}{2:00}{3:00}{4:00}", + gfax.timeToSend.Year, + gfax.timeToSend.Month, + gfax.timeToSend.Day, + gfax.timeToSend.Hour, + gfax.timeToSend.Minute); + + string jid = job_new(); + //TODO try catch exception here + //#item[1] is the name #item[2] is the company + + job_param_set("FROMUSER", Environment.UserName); + job_param_set("LASTTIME", "000259"); + job_param_set("SENDTIME", tts); + job_param_set("MAXDIALS", "12"); + job_param_set("MAXTRIES", "3"); + job_param_set("SCHEDPRI", "127"); + job_param_set("DIALSTRING", contact.PhoneNumber); + job_param_set("NOTIFYADDR", emailAddress); + job_param_set("VRES", resolution); + job_param_set("PAGEWIDTH", "215"); + job_param_set("PAGELENGTH", "279"); + job_param_set("NOTIFY", emailNotify); //can be "none" or "done" + job_param_set("PAGECHOP", "default"); + job_param_set("CHOPTHRESHOLD", "3"); + job_param_set("DOCUMENT", remote_fname); + job_submit(); + } + + public bool getfile (string fname) + { + G_ProgressBar pbar; + TcpClient myclient; + NetworkStream mystream; + FileStream fp; + string data; + double fsize = 0; + double totalBytes = 0; + double percent = 0; + + // get the file size for the receive progress bar + write(mainstream, String.Concat("SIZE recvq/", fname, "\n")); + data = read(mainstream, mainclient); + try { + string[] s = data.Split(); + fsize = Convert.ToDouble(s[1]); + } catch (Exception e) { + Console.WriteLine("Couldn't get file size"); + Console.WriteLine("Hylafax exception {0}", e); + return (false); + } + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.getfile] \"File size is : {0}", fsize); + } + + // assume we have permission to open file + permission = true; + // PASV, RETR + myclient = recvfile_open(fname); + if (Settings.Faxtracing == true) { + Console.WriteLine("[Hylafax.getfile] Got tcpclient"); + } + + mystream = myclient.GetStream(); + if (Settings.Faxtracing == true) { + Console.WriteLine("[Hylafax.getfile] Stream is open"); + } + + if (!permission) { + return (false); + } + + try { + fp = new FileStream(String.Concat(gfax.SpoolDirectory,"/tif/",fname), FileMode.Create); + } catch (Exception e) { + Console.WriteLine(e.ToString()); + return(false); + } + + byte[] bytes = new byte[256]; + + do { + try { + gfax.MainProgressBar.Fraction = percent; + while (Gtk.Application.EventsPending ()) + Gtk.Application.RunIteration (); + + int len = mystream.Read(bytes, 0, bytes.Length); + if (len > 0 ) { + totalBytes = totalBytes + len; + percent = totalBytes / fsize; + if (percent <= 1.0) + gfax.MainProgressBar.Fraction = percent; + //GLib.MainContext.Iteration (); + while (Gtk.Application.EventsPending ()) + Gtk.Application.RunIteration (); + fp.Write(bytes,0,len); + } + } catch ( Exception e ) { + Console.WriteLine(e.ToString()); + return(false); + } + // Seems if we don't sleep here for a bit, we never read + // all the data??? Maybe a Hylafax thing. + System.Threading.Thread.Sleep(1); + + } while (mystream.DataAvailable); + + fp.Close(); + recvfile_close(myclient); + + // valid file received + return(true); + } + + + + private string job_new () + { + string data; + string[] tmp; + //string jobid; + + try { + write(mainstream, "JOB default\n"); + data = read(mainstream, mainclient); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.job_new] \"JOB default\" data returned : {0}", data); + } + + write(mainstream, "JNEW\n"); + data = read(mainstream, mainclient); + // data = 200 New job created: jobid: 14433 groupid: 14433. + tmp = data.Split(' '); + + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.job_new] \"JNEW\" data returned : {0}", data); + } + + } catch (Exception e) { + Console.WriteLine("Hylafax exception {0}", e); + return (""); + } + + // jobid might need to be Convert.ToInt32 + return tmp[5]; + } + + public void job_param_set (string pname, string pvalue) + { + string data; + + write(mainstream, "JPARM " + pname + " " + pvalue +"\n"); + data = read(mainstream, mainclient); + if (Settings.Faxtracing == true) { + Console.Write("[hylafax.job_param_set] \"JPARM\" data returned : {0}", data); + } + } + + public void job_submit () + { + string data; + + write(mainstream, "JSUBM\n"); + data = read(mainstream, mainclient); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.job_submit] \"JSUBM\" data returned : {0}", data); + } + } + + private TcpClient storefile_open () + { + TcpClient myclient = new TcpClient(); + NetworkStream mystream; + IPAddress ipaddr; + int ipport; + string data; + + write(mainstream, "PASV\n"); + data = read(mainstream, mainclient); + + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.storefile_open] data returned : {0}", data); + } + + // dig out ip address and port for new connection + ipaddr = get_ip_addr(data); + ipport = get_ip_port(data); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.storefile_open] ipaddr, port : {0}, {1}", ipaddr, ipport); + } + + try { + myclient.Connect(ipaddr, ipport); + } + catch (Exception e ) { + Console.WriteLine(e.ToString()); + // handle error here + } + + mystream = myclient.GetStream(); + write(mainstream, "STOT\n"); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.storefile_open] wrote STOT"); + } + data = read(mainstream, mainclient); + //data = 150 FILE: /tmp/doc1097.ps (Opening new data connection). + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.storefile_open] returned from STOT : {0}", data); + } + return myclient; + } + + private string storefile_close(TcpClient tc) + { + string data; + string[] s; + string fn; + + tc.Close(); + data = read(mainstream, mainclient); + // data = 226 Transfer complete (FILE: /tmp/doc1101.ps). + // TODO error checking + + // remove white space first, Arrgggh! + fn = data.Trim(); + s = fn.Split(' '); + + return(s[4].TrimEnd(')','.')); + } + + private TcpClient recvfile_open (string fname) + { + TcpClient myclient = new TcpClient(); + NetworkStream mystream; + IPAddress ipaddr; + int ipport; + string data; + + write(mainstream, "PASV\n"); + data = read(mainstream, mainclient); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.recvfile_open] data returned : {0}", data); + } + + // dig out ip address and port for new connection + ipaddr = get_ip_addr(data); + ipport = get_ip_port(data); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.recvfile_open] ipaddr, port : {0}, {1}", ipaddr, ipport); + } + + try { + myclient.Connect(ipaddr, ipport); + } + catch (Exception e ) { + Console.WriteLine(e.ToString()); + // handle error here + } + + mystream = myclient.GetStream(); + write(mainstream, "TYPE I\n"); + data = read(mainstream, mainclient); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.recvfile_open] data returned : {0}", data); + } + + write(mainstream, String.Concat("RETR recvq/", fname, "\n")); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.recvfile_open] wrote RETR"); + } + data = read(mainstream, mainclient); + + if (data.Substring(0,3) == "550") + permission = false; + //data = returned from RETR : 550 recvq/fax000000018.tif: Operation not permitted. + //data = returned from RETR : 150 Opening new data connection for recvq/fax000000018.tif (2793 bytes). + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.recvfile_open] returned from RETR : {0}", data); + } + return myclient; + } + + private string recvfile_close(TcpClient tc) + { + string data; + string[] s; + string fn; + + tc.Close(); + data = read(mainstream, mainclient); + // data = 226 Transfer complete (FILE: /tmp/doc1101.ps). + // TODO error checking + + // remove white space first, Arrgggh! + //fn = data.Trim(); + //s = fn.Split(' '); + + //return(s[4].TrimEnd(')','.')); + return ""; + } + +/* + private string getfolder (string folder) + { + TcpClient myclient = new TcpClient(); + NetworkStream mystream; + IPAddress ipaddr; + int ipport; + string jobfmt; + + write(mainstream, "PASV\n"); + string data = read(mainstream, mainclient); + + // dig out ip address and port for new connection + ipaddr = get_ip_addr(data); + ipport = get_ip_port(data); + + try { + myclient.Connect(ipaddr, ipport); + } + catch (Exception e ) { + Console.WriteLine(e.ToString()); + // handle error here + } + + mystream = myclient.GetStream(); + /* + RCVFMT (receive) + %4p%1z %14.14s %7t %f + p - number of pages + z - * if still receiving, <space> otherwise + s - sender (TIS) + t - time received + f - filename + + 1= =Malaspina Univ=16Oct06=fax000000018.tif + + JOBFMT (send, done) + j - Job identifier + e - Phone number + a - Job state (one-character symbol) + o - Job owner + P - # pages transmitted/total # pages to transmit + D - Total # dials/maximum # dials + s - Job status information from last failure + Y - Scheduled date and time + */ +/* // set the job format string + if (folder == "doneq" || folder == "sendq") { + jobfmt = "\"%-4j=%-14e=%1a=%-12o=%-5P=%-5D=%.35s=%-19Y\""; + write(mainstream, "JOBFMT "+jobfmt+"\n"); + data = read(mainstream, mainclient); + } + if (folder == "recvq") { + jobfmt = "\"%4p=N%1z=%14.14s=%7t=%f\""; + write(mainstream, "RCVFMT "+jobfmt+"\n"); + data = read(mainstream, mainclient); + } + write(mainstream, "LIST "+folder+"\n"); + data = read(mystream, myclient); + + + #if DEBUGHYLAFAX + Console.WriteLine("[hylafax.getfolder] list folder data : {0}", data); + Console.WriteLine("[hylafax.getfolder] data length : {0}", data.Length); + #endif + + myclient.Close(); + return data; + } +*/ + + private void asyncgetfolder (string folder) + { + TcpClient myclient = new TcpClient(); + IPAddress ipaddr; + int ipport; + string jobfmt; + + write(mainstream, "PASV\n"); + string data = read(mainstream, mainclient); + + // dig out ip address and port for new connection + ipaddr = get_ip_addr(data); + ipport = get_ip_port(data); + + try { + myclient.Connect(ipaddr, ipport); + } + catch (Exception e ) { + Console.WriteLine(e.ToString()); + // handle error here + } + + /* + RCVFMT (receive) + %4p%1z %14.14s %7t %f + p - number of pages + z - * if still receiving, <space> otherwise + s - sender (TIS) + t - time received + f - filename + + 1= =Malaspina Univ=16Oct06=fax000000018.tif + + JOBFMT (send, done) + j - Job identifier + e - Phone number + a - Job state (one-character symbol) + o - Job owner + P - # pages transmitted/total # pages to transmit + D - Total # dials/maximum # dials + s - Job status information from last failure + Y - Scheduled date and time + */ + // set the job format string + if (folder == "doneq" || folder == "sendq") { + jobfmt = "\"%-4j=%-14e=%1a=%-12o=%-5P=%-5D=%.35s=%-19Y\""; + write(mainstream, "JOBFMT "+jobfmt+"\n"); + data = read(mainstream, mainclient); + } + if (folder == "recvq") { + jobfmt = "\"%4p=N%1z=%28.28s=%7t=%f\""; + write(mainstream, "RCVFMT "+jobfmt+"\n"); + data = read(mainstream, mainclient); + } + write(mainstream, "LIST "+folder+"\n"); + //data = read(mystream, myclient); + asyncread(myclient, folder); + } + + private IPAddress get_ip_addr (string ipdata) + { + int index = ipdata.IndexOf("("); + int len = ipdata.IndexOf(")") - index; + string s = ipdata.Substring(index + 1, len - 1 ); + char[] splitter = {','}; + string[] sa = s.Split(splitter); + string sipaddr = String.Concat(sa[0],".",sa[1],".",sa[2],".",sa[3]); + return IPAddress.Parse(sipaddr); + } + + private int get_ip_port (string ipdata) + { + // find port returned + int index = ipdata.IndexOf("("); + int len = ipdata.IndexOf(")") - index; + string s = ipdata.Substring(index + 1, len - 1 ); + char[] splitter = {','}; + string[] sa = s.Split(splitter); + return (Convert.ToInt32(sa[4]) * 256 + Convert.ToInt32(sa[5])); + } + + + private void write (NetworkStream sock, string s) + { + byte[] bytes = Encoding.ASCII.GetBytes(s); + sock.Write(bytes, 0, bytes.Length); + } + + + private string read (NetworkStream str, TcpClient c) + { + StringBuilder buf = new StringBuilder(); + byte[] bytes = new byte[256]; + + do { + try { + int len = str.Read(bytes, 0, bytes.Length); + if (len > 0 ) { + buf.Append(Encoding.ASCII.GetString(bytes,0,len)); + } + } catch ( Exception e ) { + Console.WriteLine("Network IO problem " + e.ToString()); + } + // Seems if we don't sleep here for a bit, we never read + // all the data??? Maybe a Hylafax thing. + System.Threading.Thread.Sleep(5); + + } while (str.DataAvailable); + return (buf.ToString()); + } + + + //public void asyncread (TcpClient sock, string readType) + private void asyncread (TcpClient sock, string readType) + { + gfax.activeNetwork = true; + if (readType == "status") { + gfax.asyncServerMessageBuffer = ""; + } else { + gfax.asyncFolderMessageBuffer = ""; + } + + StateObject state = new StateObject(); + state.client = sock; + state.readType = readType; + NetworkStream stream = sock.GetStream(); + + if (stream.CanRead) { + try { + IAsyncResult ar = stream.BeginRead (state.buffer, 0, StateObject.BufferSize, + new AsyncCallback(myReadCallBack), state); + } catch ( Exception e ) { + Console.WriteLine("Network IO problem " + e.ToString()); + } + } + } + + + //======================================================== + //public static void myReadCallBack(IAsyncResult ar ) + private static void myReadCallBack(IAsyncResult ar ) + { + int numberOfBytesRead; + StateObject state = (StateObject) ar.AsyncState; + NetworkStream mas = state.client.GetStream(); + string type = null; + + numberOfBytesRead = mas.EndRead(ar); + state.totalBytesRead += numberOfBytesRead; + + //Console.WriteLine("Byes read ---------------> {0}", numberOfBytesRead); + if ( numberOfBytesRead > 0) { + state.messageBuffer.Append(Encoding.ASCII.GetString(state.buffer, 0, numberOfBytesRead)); + mas.BeginRead(state.buffer, 0, StateObject.BufferSize, + new AsyncCallback(myReadCallBack), state); + } else { + mas.Close(); + state.client.Close(); + //Console.WriteLine("Byes read ---------------> {0}", state.totalBytesRead); + //Console.WriteLine("You received the following message : {0} " + state.messageBuffer); + if (state.readType == "status") { + gfax.asyncServerMessageBuffer = state.messageBuffer.ToString(); + } else { + gfax.asyncFolderMessageBuffer = state.messageBuffer.ToString(); + } + gfax.asyncReadType = state.readType; + mas = null; + state = null; + gfax.activeNetwork = false; + } + } + + public void job_select (string jobid) + { + write(mainstream, "JOB " + jobid + "\n"); + string s = read(mainstream, mainclient); + #if DEBUGHYLAFAX + Console.WriteLine("[hylafax.select] returned: {0}", s); + #endif + } + + public void job_kill () + { + write (mainstream, "JKILL\n"); + string s = read(mainstream, mainclient); + #if DEBUGHYLAFAX + Console.WriteLine("[hylafax.kill] returned: {0}", s); + #endif + } + + public void job_delete () + { + write (mainstream, "JDELE\n"); + string s = read(mainstream, mainclient); + #if DEBUGHYLAFAX + Console.WriteLine("[hylafax.delete] returned: {0}", s); + #endif + } + + public void job_suspend () + { + write (mainstream, "JSUSP\n"); + string s = read(mainstream, mainclient); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.suspend] returned: {0}", s); + } + } + + // Returns + // 550 fax000000019.tif: Operation not permitted. + // + public int deletefile (string name) + { + write (mainstream, String.Concat("DELE ", "recvq/", name, "\n")); + string s = read(mainstream, mainclient); + if (s.Substring(0,3) == "550") + return(1); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.deletefile] returned: {0}", s); + } + return (0); + } + + + private void job_param (string parms) + { + write (mainstream, "JPARM " + parms + "\n"); + string s = read(mainstream, mainclient); + #if DEBUGHYLAFAX + Console.WriteLine("[hylafax.param] returned: {0}", s); + #endif + } + + public void job_reset (string parms) + { + write (mainstream, "JREST " + parms + "\n"); + string s = read(mainstream, mainclient); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.reset] returned: {0}", s); + } + + } + + + private void timezone (string name) // can be "LOCAL" or "GMT" + { + write (mainstream, "TZONE " + name + "\n"); + string s = read(mainstream, mainclient); + if (Settings.Faxtracing == true) { + Console.WriteLine("[hylafax.timezone] returned: {0}", s); + } + } + } +} diff --git a/src/main.cs b/src/main.cs new file mode 100644 index 0000000..e44b897 --- /dev/null +++ b/src/main.cs @@ -0,0 +1,243 @@ +// GFAX - Gnome fax application +// Copyright (C) 2003 - 2008 George A. Farris +// +// 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 3 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 Library 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. + +namespace gfax { + using GLib; + using Gtk; + using GtkSharp; + using Mono.Unix; + using System; + using System.IO; + using System.Collections; + using System.Text; //Encoding.ASCII.GetBytes + using System.Threading; + using System.Diagnostics; + + + + public class gfax + { + // Gfax Global variables ( ya, ya I know) + // + // list of contacts of type Contact to xmit, we use this everywhere so it is + // simpler to make it public and global. + public static ArrayList Destinations = new ArrayList(); + public static DateTime timeToSend; + public static bool quitAfterSend = false; + public static bool fromSendWizard = false; + public static bool sendWizardResolution = false; + public static bool sendWizardEmailNotify = false; + public static string sendWizardEmailAddress = null; + public static string hylafaxPassword = null; + public static string ConfigDirectory = null; + public static string SpoolDirectory = null; + public static bool activeNetwork = false; + public static Gnome.AppBar GAppbar = null; + public static Gtk.ProgressBar MainProgressBar = null; + public static Gtk.TextBuffer GStatusTextBuffer = null; + public static Gtk.Window MainWindow = null; + public static string asyncFolderMessageBuffer = ""; + public static string asyncServerMessageBuffer = ""; + public static string asyncReadType = ""; + + public static Efax efax; + public static Status Status; + public static Pulser Pulser; + + public static string filename = null; + public static string[] pargs; + + const bool TOPLEVEL = true; + + + public static void Main (string[] args) + { + + string HOMEDIR = Environment.GetEnvironmentVariable("HOME"); + string USER = Environment.GetEnvironmentVariable("USER"); + ConfigDirectory = HOMEDIR + "/.config/gfax"; + SpoolDirectory = HOMEDIR + "/.local/share/gfax/spool"; + pargs = args; + + // TODO put this is try/catch + if ( !Directory.Exists(ConfigDirectory)) { + if ( !Directory.Exists(HOMEDIR + "/.config")) { + Directory.CreateDirectory(HOMEDIR + "/.config"); + } + // Move data from old ~/.etc directory + if ( Directory.Exists(HOMEDIR + "/.etc/gfax")) { + Directory.Move(HOMEDIR + "/.etc/gfax", ConfigDirectory); + } else { + Directory.CreateDirectory(ConfigDirectory); + } + } + if ( !Directory.Exists(HOMEDIR + "/.local/share/gfax/spool") ) { + if ( !Directory.Exists(HOMEDIR + "/.local/share/gfax") ) { + if ( !Directory.Exists(HOMEDIR + "/.local/share") ) { + if ( !Directory.Exists(HOMEDIR + "/.local") ) + Directory.CreateDirectory(HOMEDIR + "/.local"); + Directory.CreateDirectory(HOMEDIR + "/.local/share"); + } + Directory.CreateDirectory(HOMEDIR + "/.local/share/gfax"); + } + Directory.CreateDirectory(HOMEDIR + "/.local/share/gfax/spool"); + Directory.CreateDirectory(HOMEDIR + "/.local/share/gfax/spool/doneq"); + Directory.CreateDirectory(HOMEDIR + "/.local/share/gfax/spool/recq"); + } + + // Clean out the spool/tif directory - incoming faxes + if ( !Directory.Exists(HOMEDIR + "/.local/share/gfax/spool/tif")) { + Directory.CreateDirectory(HOMEDIR + "/.local/share/gfax/spool/tif"); + } else { + Directory.Delete(HOMEDIR + "/.local/share/gfax/spool/tif/", true); + Directory.CreateDirectory(HOMEDIR + "/.local/share/gfax/spool/tif"); + } + + + + // Initialize GETTEXT + Catalog.Init ("gfax", Defines.GNOME_LOCALE_DIR); + + // handle command line args ourselves + for (int i=0; i < args.Length; i++ ) { + //Console.WriteLine("{0} {1}", i, args[i]); + switch (args[i]) + { + case "--help" : + Console.WriteLine (Catalog.GetString("Gfax help...")); + Console.WriteLine ("Gfax spool dir -> {0}", SpoolDirectory); + break; + case "-f" : // file name is present + filename = args[i+1]; + break; + //case "-q" : // immediately quit after sending fax + // filename = args[i+1]; + // break; + default: + if (File.Exists(args[i])) + filename = args[i]; + break; + } + } + + try { + if ( Settings.RunSetupAtStart ) { + // Set some default preferences. + Settings.TransmitAgent = "efax"; + Settings.SendNow = true; + Settings.EfaxModemDevice = "ttyS0"; + Settings.RefreshQueueInterval = 15; + Settings.RefreshQueueEnabled = true; + } + } catch (Exception e) { + //TODO HIG love required + G_Message gm = new G_Message( + Catalog.GetString( +@"Gconfd cannot find your settings. +If you are running Gfax immediately +after an installation, you may have +to log out and log back in again."), TOPLEVEL); + Console.WriteLine("Exception in main.cs {0}", e); + Environment.Exit(0); + } + + // If we have a file name run the send dialog + if (filename != null) { + GfaxSend sd = new GfaxSend (filename, args); + FileInfo f = new FileInfo(filename); + + // send the faxes + if (sd.DoSend) { + fromSendWizard = true; + + // Start the fax daemon if efax + if (Settings.TransmitAgent == "efax") { + efax = new Efax(); + efax.run_efaxd(); + } + + Fax.sendfax(filename); + // delete the spool file (~.local/share/gfax/spool/D.*) + if (File.Exists(String.Concat(SpoolDirectory, "/", f.Name))) + File.Delete(String.Concat(SpoolDirectory, "/", f.Name)); + + //if (!quitAfterSend) { + //Gfax gf = new Gfax (filename, args); + //} + } + + // delete the spool file that gfaxlpr created if it exists + if (File.Exists(String.Concat("/var/spool/gfax/", USER, "/", f.Name))) + File.Delete(String.Concat("/var/spool/gfax/", USER, "/", f.Name)); + + }else { + // check to see if we've run before, if so gfax will be there + + if ( !Directory.Exists("/var/spool/gfax/" + USER)) { + Directory.CreateDirectory("/var/spool/gfax/" + USER); + } + + FileSystemWatcher watcher = new FileSystemWatcher(); + watcher.Path = "/var/spool/gfax/" + USER; + + watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite + | NotifyFilters.FileName | NotifyFilters.DirectoryName; + // Only watch text files. + watcher.Filter = "*"; + watcher.Created += new FileSystemEventHandler(TIOnChanged); + // Begin watching. + watcher.EnableRaisingEvents = true; + + // Start the fax daemon if efax + if (Settings.TransmitAgent == "efax") { + efax = new Efax(); + efax.run_efaxd(); + } + + Gfax gf = new Gfax (filename, args); + } + + } + + // Define the event handlers. + private static void TIOnChanged(object source, FileSystemEventArgs e) + { + // Specify what is done when a file is changed, created, or deleted. + Console.WriteLine("File---: " + e.FullPath + " " + e.ChangeType); + //GfaxSend sd = new GfaxSend ("/home/george/log.txt", pargs); + + quitAfterSend = true; + + ProcessStartInfo pidInfo = new ProcessStartInfo(); + pidInfo.FileName = "gfax"; + + pidInfo.Arguments = String.Concat("-f ",e.FullPath + " " + e.ChangeType); + + if (Settings.Faxtracing == true) { + if (Settings.TransmitAgent == "efax") { + Console.WriteLine("[Efax.send_init]\n {0}", pidInfo.Arguments); + } + } + + System.Diagnostics.Process pid = System.Diagnostics.Process.Start(pidInfo); + pid.WaitForExit(); + + + } + + } +} diff --git a/src/newphonebook.cs b/src/newphonebook.cs new file mode 100755 index 0000000..1424977 --- /dev/null +++ b/src/newphonebook.cs @@ -0,0 +1,187 @@ +// GFAX - Gnome fax application +// Copyright (C) 2003 - 2008 George A. Farris +// +// 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 3 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. + +//************************************************************************ +// NewPhoneBook class +// +// A new phone book druid, should make it easier for people to create +// new phone books. The old way was a little confusing. +// + +namespace gfax { + using Mono.Unix; + using System; + using System.IO; + using GLib; + using Gtk; + using Gnome; + using Glade; + using GConf.PropertyEditors; + using GtkSharp; + using System.Runtime.InteropServices; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + + public class NewPhoneBook + { + [Glade.Widget] Gtk.Dialog NewPhoneBookDialog; + [Glade.Widget] Gnome.Druid NewPhoneBookDruid; + [Glade.Widget] Gnome.DruidPage EvoDruidPageStandard; + [Glade.Widget] Gnome.DruidPage druidpagestandard12; + [Glade.Widget] Gtk.RadioButton GfaxRadioButton; + [Glade.Widget] Gtk.RadioButton EvolutionRadioButton; + [Glade.Widget] Gtk.RadioButton DatabaseRadioButton; + [Glade.Widget] Gtk.RadioButton LDAPRadioButton; + [Glade.Widget] Gtk.Entry NewPhoneBookNameEntry; + [Glade.Widget] Gtk.TreeView EvolutionTreeView; + + // Properties + ArrayList booknames; + string phonebooktype; + + Gtk.ListStore store; + G_ListView view; + + const int COLUMN_0 = 0; + const int COLUMN_1 = 1; + + public NewPhoneBook () + { + booknames = new ArrayList(); + + Glade.XML xml = new Glade.XML (null, "gfax.glade","NewPhoneBookDialog",null); + xml.Autoconnect (this); + + GfaxRadioButton.Active = true; + + EvolutionRadioButton.Sensitive = true; + // turn these off until somewhere near supported + DatabaseRadioButton.Visible = false; + LDAPRadioButton.Visible = false; + + store = new ListStore( + typeof (Boolean), + typeof (string)); + + view = new G_ListView(EvolutionTreeView, store); + + view.AddColumnTitleToggle(Catalog.GetString("Use"), 0, COLUMN_0); + view.AddColumnTitle(Catalog.GetString("Phone Book"), 0, COLUMN_1); + + EvolutionTreeView.HeadersVisible = true; + + NewPhoneBookDruid.ShowAll(); + } + + public ArrayList PhoneBookNames + { + get { return booknames; } + } + + public string PhoneBookType + { + get { return phonebooktype; } + } + + public void Run() + { + NewPhoneBookDialog.Run(); + } + + private void on_NewPhoneBookDialog_delete_event (object o, DeleteEventArgs args) + { + NewPhoneBookDialog.Hide(); + NewPhoneBookDialog.Dispose(); + args.RetVal = true; + } + + private void on_NewPhoneBookDruidEdge_finish (object o, Gnome.FinishClickedArgs args) + { + + if (GfaxRadioButton.Active) { + phonebooktype = "gfax"; + booknames.Add( NewPhoneBookNameEntry.Text ); + } else if (EvolutionRadioButton.Active) { + phonebooktype = "evolution"; + + Gtk.TreeIter iter = new Gtk.TreeIter(); + + // Get the first row. + store.GetIterFirst(out iter); + + try { + if ( (bool)store.GetValue(iter, 0) ) { // if use is true (toggle set) + booknames.Add( (string)store.GetValue(iter, 1) ); + } + } catch (Exception e) {} + + // get the rest of the rows + while (store.IterNext(ref iter)) { + + try { + if ( (bool)store.GetValue(iter, 0) ) { + booknames.Add( (string)store.GetValue(iter, 1) ); + } + } + catch (Exception e) {} + } + } + else if (DatabaseRadioButton.Active) + phonebooktype = "sql"; + else if (LDAPRadioButton.Active) + phonebooktype = "ldap"; + + NewPhoneBookDialog.Hide(); + NewPhoneBookDialog.Dispose(); + } + + private void on_NewPhoneBookDruid_cancel (object o, EventArgs args) + { + NewPhoneBookDialog.Hide(); + NewPhoneBookDialog.Dispose(); + } + + private void on_druidpagestandard12_next (object o, Gnome.NextClickedArgs args) + { + // we're on the gfax phone book enter name pages + // skip to finish on next signal + NewPhoneBookDruid.Page = EvoDruidPageStandard; + } + + + private void on_BookDruidPageStandard_next (object o, Gnome.NextClickedArgs args) + { + // skip next page if active + if (EvolutionRadioButton.Active) { + NewPhoneBookDruid.Page = druidpagestandard12; + + EdsPhoneBooks eds = new EdsPhoneBooks(); + ArrayList ebooks = new ArrayList(); + ebooks = eds.GetPhoneBooks(); + + Gtk.TreeIter iter = new Gtk.TreeIter(); + + IEnumerator enu = ebooks.GetEnumerator(); + while ( enu.MoveNext() ) { + iter = store.AppendValues(false, enu.Current); + EvolutionTreeView.Model = store; + } + } + } + } +} diff --git a/src/phonebook.cs b/src/phonebook.cs new file mode 100755 index 0000000..fbb8621 --- /dev/null +++ b/src/phonebook.cs @@ -0,0 +1,386 @@ +// GFAX - Gnome fax application +// Copyright (C) 2003 - 2008 George A. Farris +// +// 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 3 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 Library 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. + +namespace gfax { + using Mono.Unix; + using System; + using System.IO; + using System.Text; + using System.Collections; + + // Phone book that holds multiple numbers + public class Phonebook + { + public string Name; //Name book is called by + public string Path; //Filename including path + public string Type; // Type of phone book (gfax,gcard etc) + } + + // Individual contact in phone book + public class GfaxContact + { + public string Organization; + public string PhoneNumber; + public string ContactPerson; + } + + public class Phonetools + { + public static Phonebook[] get_phonebooks () + { + StreamReader infile = null; + string buf; + bool migrate = false; + + Phonebook[] pbooks = null; + + // TODO get location from gconf + string HOMEDIR = Environment.GetEnvironmentVariable("HOME"); + string PHONEBOOKS = gfax.ConfigDirectory + "/phonebooks"; + + #if DEBUG + Console.WriteLine("[Phonebook] Reading phonebook file"); + #endif + + int numberOfBooks = get_number_of_books(); + pbooks = new Phonebook[numberOfBooks]; + + if (numberOfBooks == 0) { + return (pbooks); + } + + + try { + infile = File.OpenText(PHONEBOOKS); + int i = 0; + + while ( (buf = infile.ReadLine()) != null ) { + switch (buf.Trim()) { + case "<book>" : + // TODO more robust file reading + Phonebook c = new Phonebook(); + c.Name = strip_tag(infile.ReadLine(), "name"); + c.Type = strip_tag(infile.ReadLine(), "type"); + c.Path = strip_tag(infile.ReadLine(), "path"); + + // Migrate from old location + if (c.Type == "gfax") { + if (Path.GetDirectoryName(c.Path) == HOMEDIR + "/.etc/gfax") { + c.Path = gfax.ConfigDirectory + "/" + Path.GetFileName(c.Path); + migrate = true; + } + } + + pbooks[i++] = c; + continue; + } + } + + infile.Close(); + if (migrate) + save_phonebooks(pbooks); + return pbooks; + } + catch (Exception e) { + Console.WriteLine("get_phonebooks - Exception in phonebook.cs {0}", e); + return pbooks; + } + + } + + // save or create phonebooks files + public static void save_phonebooks (Phonebook[] pbooks) + { + StreamWriter outfile; + + // TODO get location from gconf + string PHONEBOOKS = gfax.ConfigDirectory + "/phonebooks"; + + try { + outfile = File.CreateText(PHONEBOOKS); + } catch (Exception e) { + Console.WriteLine("Exception in phonebook.cs {0}", e); + return; + } + + outfile.WriteLine("<gfax>"); + Console.WriteLine("Len :{0}", pbooks.Length); + foreach (Phonebook p in pbooks) { + outfile.WriteLine(" <book>"); + outfile.WriteLine(" <name>" + p.Name + "</name>"); + outfile.WriteLine(" <type>" + p.Type + "</type>"); + outfile.WriteLine(" <path>" + p.Path + "</path>"); + outfile.WriteLine(" </book>"); + } + outfile.WriteLine("</gfax>"); + outfile.Close(); + } + + public static void delete_book (string book) + { + StreamReader infile = null; + string buf; + string deleteme = null; + Phonebook[] pbooks = null; + + // make array size less 1 because we're deleting 1 + pbooks = new Phonebook[get_number_of_books() - 1]; + + // TODO get location from gconf + string PHONEBOOKS = gfax.ConfigDirectory + "/phonebooks"; + string type = ""; + try { + infile = File.OpenText(PHONEBOOKS); + int i = 0; + + // iterate through the phonebook file and skip past book to delete + while ( (buf = infile.ReadLine()) != null ) { + switch (buf.Trim()) { + case "<book>" : + // TODO more robust file reading + Phonebook c = new Phonebook(); + c.Name = strip_tag(infile.ReadLine(), "name"); + c.Type = strip_tag(infile.ReadLine(), "type"); + c.Path = strip_tag(infile.ReadLine(), "path"); + + if (c.Name != book) + pbooks[i++] = c; + else { + deleteme = c.Path; + type = "gfax"; + } + continue; + } + } + infile.Close(); + save_phonebooks(pbooks); + + if (type == "gfax") + if (File.Exists(deleteme)) + File.Delete(deleteme); + } + catch (Exception e) { + Console.WriteLine("delete_book - Exception in phonebook.cs {0}", e); + return; + } + } + + // Create or add the new phone book to the "phonebooks" file. + public static void add_book (Phonebook p) + { + StreamReader infile = null; + string buf; + Phonebook[] pbooks = null; + + // make array plus 1 because we're adding 1 + pbooks = new Phonebook[get_number_of_books() + 1]; + + // TODO get location from gconf + string PHONEBOOKS = gfax.ConfigDirectory + "/phonebooks"; + + if (p.Type == "gfax") { + // add default path if not specified + if (Path.GetDirectoryName(p.Path) == "") + p.Path = gfax.ConfigDirectory + p.Path; + } + // Create the file. + if (!File.Exists(PHONEBOOKS)) { + FileStream fs = File.Create(PHONEBOOKS); + fs.Close(); + } + + int i = 0; + try { + infile = File.OpenText(PHONEBOOKS); + + while ( (buf = infile.ReadLine()) != null ) { + switch (buf.Trim()) { + case "<book>" : + // TODO more robust file reading + Phonebook c = new Phonebook(); + c.Name = strip_tag(infile.ReadLine(), "name"); + c.Type = strip_tag(infile.ReadLine(), "type"); + c.Path = strip_tag(infile.ReadLine(), "path"); + + pbooks[i++] = c; + continue; + } + } + infile.Close(); + } + catch (Exception e) { + // TODO catch file ops error + Console.WriteLine("add_book - Exception in phonebook.cs {0}", e); + return; + } + + + pbooks[i++] = p; // add the new book + save_phonebooks(pbooks); + } + + // save a list (ArrayList) of contacts + public static void save_phonebook_items (string book, ArrayList contacts) + { + Phonebook p; + StreamWriter outfile; + + p = get_book_from_name(book); + + if (p.Type == "gfax") { + // TODO error reporting + try { outfile = File.CreateText(p.Path); } + catch (Exception e) { + Console.WriteLine("save_phonebook_items - Exception in phonebook.cs {0}", e); + return; + } + + outfile.WriteLine("#Gfax phone book"); + + IEnumerator enu = contacts.GetEnumerator(); + while ( enu.MoveNext() ) { + GfaxContact c = new GfaxContact(); + c = (GfaxContact)enu.Current; + outfile.WriteLine("{0}:{1}:{2}",c.PhoneNumber,c.ContactPerson,c.Organization); + } + outfile.Close(); + } + } + + public static StreamReader open_phonebook (Phonebook p) + { + StreamReader infile = null; + + // If it doesn't exist yet just return + if (!File.Exists(p.Path)) + return(null); + + try { + infile = File.OpenText(p.Path); + } + catch (Exception e) { + Console.WriteLine("open_phonebook - Exception in phonebook.cs {0}", e); + return null; + } + return infile; + } + + public static ArrayList get_contacts (Phonebook p) + { + string buf = null; + string[] sa; + //char[] ca = {':',':',':'}; delete me + + ArrayList records = new ArrayList(); + StreamReader fp = null; + + // TODO add popup message + if ( p.Type == "gfax" ) { + fp = open_phonebook(p); + if (fp == null) { + Console.WriteLine(Catalog.GetString("Can't open file : {0}"), p.Path); + return records; + } + + while ( (buf = fp.ReadLine()) != null ) { + buf.Trim(); + + if (buf[0] == '#') + continue; + else { + sa = buf.Split(':'); + GfaxContact contact = new GfaxContact(); + contact.PhoneNumber = sa[0]; + contact.ContactPerson = sa[1]; + contact.Organization = sa[2]; + records.Add(contact); + } + } + + fp.Close(); + } + + if ( p.Type == "evolution" ) { + EdsPhoneBooks eds = new EdsPhoneBooks(); + ArrayList ebooks = new ArrayList(); + ebooks = eds.GetPhoneBooks(); + + IEnumerator enu = ebooks.GetEnumerator(); + while ( enu.MoveNext() ) { + if ((string)enu.Current == p.Name) { + records = eds.GetContacts((string)enu.Current); + } + } + } + + return records; + + } + + public static string strip_tag (string line, string tag) + { + string bt = "<" + tag + ">"; + string et = "</" + tag + ">"; + string s = (line.Trim()).Replace(bt, ""); + return s.Replace(et, ""); + } + + private static int get_number_of_books () + { + StreamReader infile = null; + string buf; + int count = 0; + + // TODO get location from gconf + string PHONEBOOKS = gfax.ConfigDirectory + "/phonebooks"; + + if (!File.Exists(PHONEBOOKS)) + return(0); + + try { + infile = File.OpenText(PHONEBOOKS); + } catch (Exception e) { + Console.WriteLine("get_number_of_books - Exception in phonebook.cs {0}", e); + return 0; + } + + // how many phone books do we have, Trim() removes white space + while ( (buf = infile.ReadLine()) != null ) { + if ( buf.Trim() == "<book>") { + count++; + } + } + infile.Close(); + return count; + } + + public static Phonebook get_book_from_name(string name) + { + Phonebook[] books; + //int count; delete me + + //count = get_number_of_books(); delete me + books = get_phonebooks(); + + foreach (Phonebook p in books) { + if (name == p.Name) + return p; + } + return null; + } + } +} diff --git a/src/sendphonebook.cs b/src/sendphonebook.cs new file mode 100755 index 0000000..cc1dc62 --- /dev/null +++ b/src/sendphonebook.cs @@ -0,0 +1,242 @@ +// GFAX - Gnome fax application +// Copyright (C) 2003 - 2008 George A. Farris +// +// 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 3 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 Library 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. + +namespace gfax { + using Mono.Unix; + using System; + using System.IO; + using GLib; + using Gtk; + using Gnome; + using Glade; + using GtkSharp; + using System.Runtime.InteropServices; + using System.Collections; + using System.Reflection; + + //************************************************************************ + // GfaxSendPhoneBook class + // + // + // + public class GfaxSendPhoneBook + { + Gtk.Dialog phbd; + Gtk.TreeView book, list; + //Gtk.TreeModel book_model; delete me + Gtk.ListStore book_store, list_store; + G_ListView bs, ls; + Glade.XML gsxml; + + [Glade.Widget] Gtk.Dialog PhbookDialog; + [Glade.Widget] Gtk.TreeView book_treeview; + [Glade.Widget] Gtk.TreeView list_treeview; + + const int COLUMN_0 = 0; + const int COLUMN_1 = 1; + const int COLUMN_2 = 2; + const int ALL_COLUMNS = -1; + //string parent; delete me + Phonebook[] myPhoneBooks; + + public GfaxSendPhoneBook (Glade.XML xml, string myparent) + { + + //Phonebook[] pb; delete me + + //gxml = xml; + //parent = myparent; delete me + myPhoneBooks = Phonetools.get_phonebooks(); + + if ( myPhoneBooks == null ) { + G_Message m = new G_Message(Catalog.GetString("You don't have any phone books yet.")); + m = null; + return; + } + + gsxml = new Glade.XML (null, "send-druid.glade","PhbookDialog",null); + gsxml.Autoconnect (this); + + // Get the widget so we can manipulate it + //phbd = (Gtk.Dialog) gsxml.GetWidget("PhbookDialog"); + //book = (Gtk.TreeView) gsxml.GetWidget("book_treeview"); + //list = (Gtk.TreeView) gsxml.GetWidget("list_treeview"); + phbd = PhbookDialog; + book = book_treeview; + list = list_treeview; + + book.Selection.Changed += new EventHandler (on_book_treeview_selection); + + phbd.Resizable = true; + book_store = new ListStore(typeof(string)); + book.HeadersVisible = false; + book.Selection.Mode = SelectionMode.Multiple; + + bs = new G_ListView(book, book_store); + // Got have a column title or things won't show up + bs.AddColumnTitle(Catalog.GetString("Phone books"), 0, COLUMN_0); + + + list_store = new ListStore( + typeof (string), + typeof (string), + typeof (string)); + + ls = new G_ListView(list, list_store); + ls.AddColumnTitle(Catalog.GetString("Organization"), 0, COLUMN_0); + ls.AddColumnTitle(Catalog.GetString("Phone Number"), 1, COLUMN_1); + ls.AddColumnTitle(Catalog.GetString("Contact"), 2, COLUMN_2); + list.HeadersVisible = true; + list.Selection.Mode = SelectionMode.Multiple; + + // populate the list + foreach (Phonebook p in myPhoneBooks) + bs.AddTextToRow(p.Name); + + phbd.Run(); + } + + // load the phone book + // Since we have SelectionMode.Multiple turned on we have to + // jump through these hoops in GTK-2.0 to get a selection + private void on_book_treeview_selection(object o, EventArgs args) + { + Gtk.TreeIter iter = new Gtk.TreeIter(); + //Value value = new Value(); delete me + string selectionText = null; + + book_store.GetIterFirst(out iter); + if ( book.Selection.IterIsSelected(iter)) { + selectionText = (string)book_store.GetValue(iter, 0); + } + + while (book_store.IterNext(ref iter)) { + if ( book.Selection.IterIsSelected(iter)) { + selectionText = (string)book_store.GetValue(iter, 0); + } + } + + // Ok now we can finally load the phone book + foreach (Phonebook p in myPhoneBooks) + if (p.Name == selectionText) + load_phone_book(p); + + } + + // If we double click the phonebook. + private void on_book_treeview_row_activated(object o, RowActivatedArgs args) + { + /* + ArrayList bsdest = new ArrayList(); + ArrayList contacts = new ArrayList(); + + bsdest = bs.GetSelections(COLUMN_0); + if ( bsdest.Count > 0 ) { + IEnumerator enu = bsdest.GetEnumerator(); + while ( enu.MoveNext() ) { + foreach (Phonebook p in myPhoneBooks) + if (p.Name == (string)enu.Current) + contacts = Phonetools.get_contacts(p); + + // add contacts to global desinations + IEnumerator enuc = contacts.GetEnumerator(); + while ( enuc.MoveNext() ) + gfax.Destinations.Add((Contact)enuc.Current); + } + } + + phbd.Destroy(); + */ + } + + + private void on_list_treeview_row_activated(object o, RowActivatedArgs args) + { + } + + private void on_ok_button_clicked(object o, EventArgs args) + { + ArrayList lsdest = new ArrayList(); + ArrayList bsdest = new ArrayList(); + ArrayList contacts = new ArrayList(); + + lsdest = ls.GetSelections(ALL_COLUMNS); + + // if there are indiviual entries don't do entire phonebooks + if (lsdest.Count > 0) { + IEnumerator enu = lsdest.GetEnumerator(); + while ( enu.MoveNext() ) { + GfaxContact c = new GfaxContact(); + c.Organization = (string)enu.Current; + enu.MoveNext(); + c.PhoneNumber = (string)enu.Current; + enu.MoveNext(); + c.ContactPerson = (string)enu.Current; + gfax.Destinations.Add(c); + } + } + else { + bsdest = bs.GetSelections(COLUMN_0); + if ( bsdest.Count > 0 ) { + IEnumerator enu = bsdest.GetEnumerator(); + while ( enu.MoveNext() ) { + foreach (Phonebook p in myPhoneBooks) + if (p.Name == (string)enu.Current) + contacts = Phonetools.get_contacts(p); + + // add contacts to global desinations + if (contacts.Count > 0) { + IEnumerator enuc = contacts.GetEnumerator(); + while ( enuc.MoveNext() ) + gfax.Destinations.Add((GfaxContact)enuc.Current); + } + } + } + } + + phbd.Destroy(); + } + + // loads the phone book into list_store + private void load_phone_book(Phonebook p) + { + ArrayList contacts = null; + + // Clear the list_store + list_store.Clear(); + + contacts = Phonetools.get_contacts(p); + if (contacts == null) + return; + + IEnumerator enu = contacts.GetEnumerator(); + while ( enu.MoveNext() ) { + GfaxContact c = new GfaxContact(); + c = (GfaxContact)enu.Current; + ls.AddTextToRow(c.Organization, c.PhoneNumber, c.ContactPerson); + } + } + + private void on_cancel_button_clicked(object o, EventArgs args) + { + phbd.Destroy(); + } + + } + +} |