summary refs log tree commit diff stats
path: root/src/htm/Main.cs
blob: 884b23f8a96f65238a2f8a63e57edf86797ca8ea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94<
#ifndef DIRENT_INCLUDED
#define DIRENT_INCLUDED

/*

    Declaration of POSIX directory browsing functions and types for Win32.

    Author:  Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
    History: Created March 1997. Updated June 2003.
    Rights:  See end of file.
    
*/

#ifdef __cplusplus
extern "C"
{
#endif

typedef struct DIR DIR;

struct dirent
{
    char *d_name;
};

DIR           *opendir(const char *);
int           closedir(DIR *);
struct dirent *readdir(DIR *);
void          rewinddir(DIR *);

/*

    Copyright Kevlin Henney, 1997, 2003. All rights reserved.

    Permission to use, copy, modify, and distribute this software and its
    documentation for any purpose is hereby granted without fee, provided
    that this copyright and permissions notice appear in all copies and
    derivatives.
    
    This software is supplied "as is" without express or implied warranty.

    But that said, if there are any problems please get in touch.

*/

#ifdef __cplusplus
}
#endif

#endif
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
/**
 * HexChat Theme Manager
 *
 * Copyright (C) 2012 Patrick Griffs
 * Copyright (C) 2012 Berke Viktor
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
/* using System.IO.Compression; */
using System.IO.Packaging;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;

namespace thememan
{
    public partial class HTM : Form
    {
        public string hexchatdir;
        public string themedir;

        OpenFileDialog importDialog;

        public HTM ()
        {
            InitializeComponent ();

            if (RunningOnWindows() && File.Exists("portable-mode"))
            {
                hexchatdir = ("config\\");

                if (!Directory.Exists(hexchatdir))
                {
                    MessageBox.Show("HexChat installation not found!\nCheck your .\\config folder", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Environment.Exit(1);
                }
            }
            else
            {
                /* Environment.SpecialFolder.ApplicationData
                 * Windows: %APPDATA%
                 * Unix: ~/.config
                 * Windows is case-insensitive so 'hexchat' should be fine for both
                 */
                hexchatdir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "hexchat");

                if (!Directory.Exists(hexchatdir))
                {
                    if (RunningOnWindows())
                    {
                        MessageBox.Show("HexChat installation not found!\nCheck your %APPDATA%\\HexChat folder", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);    
                    }
                    else
                    {
                        MessageBox.Show("HexChat installation not found!\nCheck your ~/.config/hexchat folder", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    
                    Environment.Exit(1);
                }
            }

            themedir = Path.Combine(hexchatdir, "themes");
            ListThemes();

            String[] arguments = Environment.GetCommandLineArgs();
            if (arguments.Length > 1)
            {
                FileInfo fi = new FileInfo(arguments[1]);
                attemptImport(fi);
            }
        }

        private bool RunningOnWindows()
        {
            if (Environment.OSVersion.ToString().ToLower().Contains("windows"))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        private void ListThemes()
        {
            themelist.Items.Clear();

            if (Directory.Exists(themedir))
            {
                foreach (string theme in Directory.GetDirectories(themedir))
                {
                    themelist.Items.Add(theme.Remove(0, themedir.Length + 1));
                }
            }
            else
            {
                Directory.CreateDirectory(themedir);
            }

            if (themelist.Items.Count == 0)
            {
                applybutton.Enabled = false;
                deleteButton.Enabled = false;
            }
            else
            {
                themelist.SetSelected(0, true);
            }
        }

        private void ShowColors(List<List<string>> themecolors)
        {
            List<Control> labels = this.Controls.OfType<Label>().Cast<Control>().OrderBy(label => label.Name).ToList();
            for (byte themecolor = 0; themecolor < themecolors.Count; themecolor++)
            {
                byte rval = Convert.ToByte(int.Parse(themecolors[themecolor][0].ToString(), System.Globalization.NumberStyles.HexNumber) / 257);
                byte gval = Convert.ToByte(int.Parse(themecolors[themecolor][1].ToString(), System.Globalization.NumberStyles.HexNumber) / 257);
                byte bval = Convert.ToByte(int.Parse(themecolors[themecolor][2].ToString(), System.Globalization.NumberStyles.HexNumber) / 257);
                
                if (themecolor <= 15)
                    labels[themecolor].BackColor = Color.FromArgb(rval, gval, bval);
                else if (themecolor == 16)
                    themecolorfgmarked.ForeColor = Color.FromArgb(rval, gval, bval);
                else if (themecolor == 17)
                    themecolorfgmarked.BackColor = Color.FromArgb(rval, gval, bval);
                else if (themecolor == 18)
                    themecolorfg.ForeColor = Color.FromArgb(rval, gval, bval);
                else if (themecolor == 19)
                {
                    themecolortextbg.BackColor = Color.FromArgb(rval, gval, bval);
                    themecolorfg.BackColor = themecolortextbg.BackColor;
                }
            }
        }

        private List<List<string>> ReadTheme(string theme)
        {
            List<List<string>> themecolors = new List<List<string>>();
            foreach (string line in File.ReadLines(Path.Combine(themedir, theme, "colors.conf")))
            {
                List<string> colors = new List<string>();
                List<string> colorlist = new List<string>();
                string[] possiblecolors = { "color_256", "color_257", "color_258", "color_259" };

                for (byte num = 16; num <=31; num++)
                    colorlist.Add("color_" + num);
                colorlist.AddRange(possiblecolors);

                string[] config = line.Split(new char[] { ' ' });
                if(colorlist.Contains(config[0]) == true)
                {
                    colors.Add(config[2]);
                    colors.Add(config[3]);
                    colors.Add(config[4]);
                    themecolors.Add(colors);
                }
            }
            return themecolors;
        }

        private void applybutton_Click_1(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("HexChat must be closed and this will overwrite your current theme!\n\nDo you wish to continue?", "Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
            if (result == DialogResult.OK)
            {
                File.Copy(Path.Combine(themedir, themelist.SelectedItem.ToString(), "colors.conf"), Path.Combine(hexchatdir, "colors.conf"), true);
                if (File.Exists(Path.Combine(themedir, themelist.SelectedItem.ToString(), "pevents.conf")))
                {
                    File.Copy(Path.Combine(themedir, themelist.SelectedItem.ToString(), "pevents.conf"), Path.Combine(hexchatdir, "pevents.conf"), true);
                }
                else if (File.Exists(Path.Combine(hexchatdir, "pevents.conf")))
                {
                    File.Delete(Path.Combine(hexchatdir, "pevents.conf"));
                }
            }
        }

        private void theme_selected(object sender, EventArgs e)
        {
            if (themelist.SelectedItem != null)
            {
                ShowColors(ReadTheme(themelist.SelectedItem.ToString()));
                applybutton.Enabled = true;
                deleteButton.Enabled = true;
            }
        }

        private void importbutton_Click_1(object sender, EventArgs e)
        {
            importDialog = new OpenFileDialog();
            importDialog.Filter = "HexChat Theme Files|*.hct";
            importDialog.FilterIndex = 1;
            importDialog.FileOk += new CancelEventHandler(importdialog_FileOk);
            importDialog.ShowDialog();
        }

        private void importdialog_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
        {
            FileInfo fi = new FileInfo(importDialog.FileName);
            attemptImport(fi);
        }

        private void attemptImport(FileInfo fi)
        {
            string themeName = fi.Name.Remove(fi.Name.Length - fi.Extension.Length);
            int result = extractTheme(fi);
            ListThemes();
            /* although a check is added to ListThemes(), this would still fail if the theme file was invalid or the theme is already installed */
            switch (result)
            {
                case 0:
                    themelist.SetSelected(themelist.FindStringExact(themeName), true);
                    /* required for command line invoking */
                    ShowColors(ReadTheme(themeName));
                    break;
                case 1:
                    MessageBox.Show("This theme is already installed!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    themelist.SetSelected(themelist.FindStringExact(themeName), true);
                    /* required for command line invoking */
                    ShowColors(ReadTheme(themeName));
                    break;
                case 2:
                    MessageBox.Show("Invalid theme file!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    break;
            }
        }
        /* gzip solution, not good enough coz we need multiple files
         * 
        public string extractTheme(FileInfo fi)
        {
            using (FileStream inFile = fi.OpenRead())
            {
                string themeName = fi.Name.Remove(fi.Name.Length - fi.Extension.Length);
                string destFolder = xchatdir + themedir + themeName;

                if (!Directory.Exists(destFolder))
                {
                    Directory.CreateDirectory(destFolder);
                }

                using (FileStream outFile = File.Create(destFolder + "\\colors.conf"))
                {
                    using (GZipStream Decompress = new GZipStream(inFile, CompressionMode.Decompress))
                    {
                        Decompress.CopyTo(outFile);
                    }
                }
                return themeName;
            }
        }
         */

        /* using System.IO.Package:
         * http://weblogs.asp.net/jgalloway/archive/2007/10/25/creating-zip-archives-in-net-without-an-external-library-like-sharpziplib.aspx
         * [Content_Types].xml must be present for every zip file
         */

        private const long BUFFER_SIZE = 4096;

        private int extractTheme(FileInfo zipFile)
        {
            string themeName = zipFile.Name.Remove(zipFile.Name.Length - zipFile.Extension.Length);
            string destFolder = Path.Combine(themedir, themeName);

            try
            {
                using (Package zip = Package.Open(zipFile.FullName, FileMode.Open, FileAccess.Read))
                {
                    PackagePartCollection parts = zip.GetParts();

                    if (Directory.Exists(destFolder))
                    {
                        return 1;
                    }
                    else
                    {
                        Directory.CreateDirectory(destFolder);
                    }

                    foreach (PackagePart part in parts)
                    {
                        /* not sure what's this good for */
                        /* String archive = part.Uri.ToString().Replace(@"/", @"\"); */
                        String destFile = destFolder + part.Uri.ToString();

                            using (FileStream outFileStream = new FileStream(destFile, FileMode.CreateNew, FileAccess.ReadWrite))
                            {
                                using (Stream inStream = part.GetStream())
                                {
                                    long bufferSize = inStream.Length < BUFFER_SIZE ? inStream.Length : BUFFER_SIZE;
                                    byte[] buffer = new byte[bufferSize];
                                    int bytesRead = 0;
                                    long bytesWritten = 0;

                                    while ((bytesRead = inStream.Read(buffer, 0, buffer.Length)) != 0)
                                    {
                                        outFileStream.Write(buffer, 0, bytesRead);
                                        bytesWritten += bufferSize;
                                    }
                                }
                            }


                    }
                }
            }
            catch (System.IO.FileFormatException)
            {
                return 2;
            }

            if (IsDirectoryEmpty(destFolder))
            {
                Directory.Delete(destFolder);
                return 2;
            }
            else
            {
                return 0;
            }
        }

        public bool IsDirectoryEmpty(string path)
        {
            return !Directory.EnumerateFileSystemEntries(path).Any();
        }

        private void deleteButton_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("Are you sure you want to delete this theme from the theme repo?\n\nYour currently applied theme won't be affected.", "Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
            if (result == DialogResult.OK)
            {
                Directory.Delete(Path.Combine(themedir, themelist.SelectedItem.ToString()), true);
                ListThemes();
                if (themelist.Items.Count == 0)
                {
                    deleteButton.Enabled = false;
                }
            }
        }



    }
}