2 * Copyright (C) 1998 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #define __APPLE_API_STRICT_CONFORMANCE
21 #define _FILE_OFFSET_BITS 64
26 #include <sys/types.h>
28 #include <sys/types.h>
31 #include <sys/utsname.h>
44 #if defined (USING_FREEBSD) || defined (__APPLE__)
45 #include <sys/sysctl.h>
53 #include <openssl/bn.h>
54 #include <openssl/rand.h>
55 #include <openssl/blowfish.h>
56 #include <openssl/aes.h>
58 #include <netinet/in.h>
69 int current_mem_usage
;
78 struct mem_block
*next
;
81 struct mem_block
*mroot
= NULL
;
84 xchat_malloc (int size
, char *file
, int line
)
87 struct mem_block
*new;
89 current_mem_usage
+= size
;
93 printf ("Out of memory! (%d)\n", current_mem_usage
);
97 new = malloc (sizeof (struct mem_block
));
102 new->file
= strdup (file
);
105 printf ("%s:%d Malloc'ed %d bytes, now \033[35m%d\033[m\n", file
, line
,
106 size
, current_mem_usage
);
112 xchat_realloc (char *old
, int len
, char *file
, int line
)
116 ret
= xchat_malloc (len
, file
, line
);
120 xchat_dfree (old
, file
, line
);
126 xchat_strdup (char *str
, char *file
, int line
)
129 struct mem_block
*new;
132 size
= strlen (str
) + 1;
133 current_mem_usage
+= size
;
137 printf ("Out of memory! (%d)\n", current_mem_usage
);
142 new = malloc (sizeof (struct mem_block
));
147 new->file
= strdup (file
);
150 printf ("%s:%d strdup (\"%-.40s\") size: %d, total: \033[35m%d\033[m\n",
151 file
, line
, str
, size
, current_mem_usage
);
157 xchat_mem_list (void)
159 struct mem_block
*cur
, *p
;
170 if (p
->line
== cur
->line
&&
171 strcmp (p
->file
, cur
->file
) == 0)
180 cur
->total
= cur
->size
;
181 totals
= g_slist_prepend (totals
, cur
);
186 fprintf (stderr
, "file line size num total\n");
191 fprintf (stderr
, "%-15.15s %6d %6d %6d %6d\n", cur
->file
, cur
->line
,
192 cur
->size
, cur
->total
/cur
->size
, cur
->total
);
198 xchat_dfree (void *buf
, char *file
, int line
)
200 struct mem_block
*cur
, *last
;
204 printf ("%s:%d \033[33mTried to free NULL\033[m\n", file
, line
);
219 printf ("%s:%d \033[31mTried to free unknown block %lx!\033[m\n",
220 file
, line
, (unsigned long) buf
);
225 current_mem_usage
-= cur
->size
;
226 printf ("%s:%d Free'ed %d bytes, usage now \033[35m%d\033[m\n",
227 file
, line
, cur
->size
, current_mem_usage
);
229 last
->next
= cur
->next
;
236 #define malloc(n) xchat_malloc(n, __FILE__, __LINE__)
237 #define realloc(n, m) xchat_realloc(n, m, __FILE__, __LINE__)
238 #define free(n) xchat_dfree(n, __FILE__, __LINE__)
239 #define strdup(n) xchat_strdup(n, __FILE__, __LINE__)
241 #endif /* MEMORY_DEBUG */
244 file_part (char *file
)
246 char *filepart
= file
;
264 path_part (char *file
, char *path
, int pathlen
)
267 char *filepart
= file_part (file
);
270 safe_strcpy (path
, file
, pathlen
);
274 char * /* like strstr(), but nocase */
275 nocasestrstr (const char *s
, const char *wanted
)
277 register const int len
= strlen (wanted
);
281 while (rfc_tolower(*s
) != rfc_tolower(*wanted
) || strncasecmp (s
, wanted
, len
))
288 errorstring (int err
)
295 return _("Remote host closed socket");
298 return strerror (err
);
302 waitline (int sok
, char *buf
, int bufsize
, int use_recv
)
310 if (recv (sok
, &buf
[i
], 1, 0) < 1)
314 if (read (sok
, &buf
[i
], 1) < 1)
317 if (buf
[i
] == '\n' || bufsize
== i
+ 1)
326 /* checks for "~" in a file and expands */
329 expand_homedir (char *file
)
336 if (file
[1] != '\0' && file
[1] != '/')
339 if (strchr(user
,'/') != NULL
)
340 *(strchr(user
,'/')) = '\0';
341 if ((pw
= getpwnam(user
+ 1)) == NULL
)
347 user
= strchr(file
, '/') != NULL
? strchr(file
,'/') : file
;
348 ret
= malloc(strlen(user
) + strlen(pw
->pw_dir
) + 1);
349 strcpy(ret
, pw
->pw_dir
);
354 ret
= malloc (strlen (file
) + strlen (g_get_home_dir ()) + 1);
355 sprintf (ret
, "%s%s", g_get_home_dir (), file
+ 1);
359 return strdup (file
);
363 strip_color (const char *text
, int len
, int flags
)
370 new_str
= g_malloc (len
+ 2);
371 strip_color2 (text
, len
, new_str
, flags
);
373 if (flags
& STRIP_ESCMARKUP
)
375 char *esc
= g_markup_escape_text (new_str
, -1);
383 /* CL: strip_color2 strips src and writes the output at dst; pass the same pointer
384 in both arguments to strip in place. */
386 strip_color2 (const char *src
, int len
, char *dst
, int flags
)
388 int rcol
= 0, bgcol
= 0;
391 if (len
== -1) len
= strlen (src
);
394 if (rcol
> 0 && (isdigit ((unsigned char)*src
) ||
395 (*src
== ',' && isdigit ((unsigned char)src
[1]) && !bgcol
)))
397 if (src
[1] != ',') rcol
--;
408 case '\003': /*ATTR_COLOR: */
409 if (!(flags
& STRIP_COLOR
)) goto pass_char
;
412 case HIDDEN_CHAR
: /* CL: invisible text (for event formats only) */ /* this takes care of the topic */
413 if (!(flags
& STRIP_HIDDEN
)) goto pass_char
;
415 case '\007': /*ATTR_BEEP: */
416 case '\017': /*ATTR_RESET: */
417 case '\026': /*ATTR_REVERSE: */
418 case '\002': /*ATTR_BOLD: */
419 case '\037': /*ATTR_UNDERLINE: */
420 case '\035': /*ATTR_ITALICS: */
421 if (!(flags
& STRIP_ATTRIB
)) goto pass_char
;
432 return (int) (dst
- start
);
436 strip_hidden_attribute (char *src
, char *dst
)
439 while (*src
!= '\000')
441 if (*src
!= HIDDEN_CHAR
)
451 #if defined (USING_LINUX) || defined (USING_FREEBSD) || defined (__APPLE__)
454 get_cpu_info (double *mhz
, int *cpus
)
465 fh
= open ("/proc/cpuinfo", O_RDONLY
); /* linux 2.2+ only */
474 if (waitline (fh
, buf
, sizeof buf
, FALSE
) < 0)
476 if (!strncmp (buf
, "cycle frequency [Hz]\t:", 22)) /* alpha */
478 *mhz
= atoi (buf
+ 23) / 1000000;
479 } else if (!strncmp (buf
, "cpu MHz\t\t:", 10)) /* i386 */
481 *mhz
= atof (buf
+ 11) + 0.5;
482 } else if (!strncmp (buf
, "clock\t\t:", 8)) /* PPC */
484 *mhz
= atoi (buf
+ 9);
485 } else if (!strncmp (buf
, "processor\t", 10))
509 sysctl(mib
, 2, &ncpu
, &len
, NULL
, 0);
512 sysctlbyname("machdep.tsc_freq", &freq
, &len
, NULL
, 0);
515 *mhz
= (freq
/ 1000000);
521 unsigned long long freq
;
532 sysctl(mib
, 2, &ncpu
, &len
, NULL
, 0);
535 sysctlbyname("hw.cpufrequency", &freq
, &len
, NULL
, 0);
538 *mhz
= (freq
/ 1000000);
548 #if defined (USING_LINUX) || defined (USING_FREEBSD) || defined (__APPLE__)
553 static char *buf
= NULL
;
562 #if defined (USING_LINUX) || defined (USING_FREEBSD) || defined (__APPLE__)
563 get_cpu_info (&mhz
, &cpus
);
566 double cpuspeed
= ( mhz
> 1000 ) ? mhz
/ 1000 : mhz
;
567 const char *cpuspeedstr
= ( mhz
> 1000 ) ? "GHz" : "MHz";
569 (cpus
== 1) ? "%s %s [%s/%.2f%s]" : "%s %s [%s/%.2f%s/SMP]",
570 un
.sysname
, un
.release
, un
.machine
,
571 cpuspeed
, cpuspeedstr
);
575 (cpus
== 1) ? "%s %s [%s]" : "%s %s [%s/SMP]",
576 un
.sysname
, un
.release
, un
.machine
);
582 buf_get_line (char *ibuf
, char **buf
, int *position
, int len
)
584 int pos
= *position
, spos
= pos
;
589 while (ibuf
[pos
++] != '\n')
602 int match(const char *mask
, const char *string
)
604 register const char *m
= mask
, *s
= string
;
606 const char *bm
, *bs
; /* Will be reg anyway on a decent CPU/compiler */
608 /* Process the "head" of the mask, if any */
609 while ((ch
= *m
++) && (ch
!= '*'))
613 if (*m
== '?' || *m
== '*')
616 if (rfc_tolower(*s
) != rfc_tolower(ch
))
625 /* We got a star: quickly find if/where we match the next char */
627 bm
= m
; /* Next try rollback here */
636 continue; /* while */
638 if (*m
== '?' || *m
== '*')
641 goto break_while
; /* C is structured ? */
645 return 1; /* mask ends with '*', we got it */
646 ch
= rfc_tolower(ch
);
647 while (rfc_tolower(*s
++) != ch
)
650 bs
= s
; /* Next try start from here */
652 /* Check the rest of the "chunk" */
660 if (*m
== '?' || *m
== '*')
663 if (rfc_tolower(*s
) != rfc_tolower(ch
))
686 for_files (char *dirname
, char *mask
, void callback (char *file
))
692 dir
= opendir (dirname
);
695 while ((ent
= readdir (dir
)))
697 if (strcmp (ent
->d_name
, ".") && strcmp (ent
->d_name
, ".."))
699 if (match (mask
, ent
->d_name
))
701 buf
= malloc (strlen (dirname
) + strlen (ent
->d_name
) + 2);
702 sprintf (buf
, "%s/%s", dirname
, ent
->d_name
);
713 tolowerStr (char *str)
717 *str = rfc_tolower (*str);
724 char *code
, *country
;
728 country_compare (const void *a
, const void *b
)
730 return strcasecmp (a
, ((domain_t
*)b
)->code
);
733 static const domain_t domain
[] =
735 {"AC", N_("Ascension Island") },
736 {"AD", N_("Andorra") },
737 {"AE", N_("United Arab Emirates") },
738 {"AF", N_("Afghanistan") },
739 {"AG", N_("Antigua and Barbuda") },
740 {"AI", N_("Anguilla") },
741 {"AL", N_("Albania") },
742 {"AM", N_("Armenia") },
743 {"AN", N_("Netherlands Antilles") },
744 {"AO", N_("Angola") },
745 {"AQ", N_("Antarctica") },
746 {"AR", N_("Argentina") },
747 {"ARPA", N_("Reverse DNS") },
748 {"AS", N_("American Samoa") },
749 {"AT", N_("Austria") },
750 {"ATO", N_("Nato Fiel") },
751 {"AU", N_("Australia") },
752 {"AW", N_("Aruba") },
753 {"AX", N_("Aland Islands") },
754 {"AZ", N_("Azerbaijan") },
755 {"BA", N_("Bosnia and Herzegovina") },
756 {"BB", N_("Barbados") },
757 {"BD", N_("Bangladesh") },
758 {"BE", N_("Belgium") },
759 {"BF", N_("Burkina Faso") },
760 {"BG", N_("Bulgaria") },
761 {"BH", N_("Bahrain") },
762 {"BI", N_("Burundi") },
763 {"BIZ", N_("Businesses"), },
764 {"BJ", N_("Benin") },
765 {"BM", N_("Bermuda") },
766 {"BN", N_("Brunei Darussalam") },
767 {"BO", N_("Bolivia") },
768 {"BR", N_("Brazil") },
769 {"BS", N_("Bahamas") },
770 {"BT", N_("Bhutan") },
771 {"BV", N_("Bouvet Island") },
772 {"BW", N_("Botswana") },
773 {"BY", N_("Belarus") },
774 {"BZ", N_("Belize") },
775 {"CA", N_("Canada") },
776 {"CC", N_("Cocos Islands") },
777 {"CD", N_("Democratic Republic of Congo") },
778 {"CF", N_("Central African Republic") },
779 {"CG", N_("Congo") },
780 {"CH", N_("Switzerland") },
781 {"CI", N_("Cote d'Ivoire") },
782 {"CK", N_("Cook Islands") },
783 {"CL", N_("Chile") },
784 {"CM", N_("Cameroon") },
785 {"CN", N_("China") },
786 {"CO", N_("Colombia") },
787 {"COM", N_("Internic Commercial") },
788 {"CR", N_("Costa Rica") },
789 {"CS", N_("Serbia and Montenegro") },
791 {"CV", N_("Cape Verde") },
792 {"CX", N_("Christmas Island") },
793 {"CY", N_("Cyprus") },
794 {"CZ", N_("Czech Republic") },
795 {"DE", N_("Germany") },
796 {"DJ", N_("Djibouti") },
797 {"DK", N_("Denmark") },
798 {"DM", N_("Dominica") },
799 {"DO", N_("Dominican Republic") },
800 {"DZ", N_("Algeria") },
801 {"EC", N_("Ecuador") },
802 {"EDU", N_("Educational Institution") },
803 {"EE", N_("Estonia") },
804 {"EG", N_("Egypt") },
805 {"EH", N_("Western Sahara") },
806 {"ER", N_("Eritrea") },
807 {"ES", N_("Spain") },
808 {"ET", N_("Ethiopia") },
809 {"EU", N_("European Union") },
810 {"FI", N_("Finland") },
812 {"FK", N_("Falkland Islands") },
813 {"FM", N_("Micronesia") },
814 {"FO", N_("Faroe Islands") },
815 {"FR", N_("France") },
816 {"GA", N_("Gabon") },
817 {"GB", N_("Great Britain") },
818 {"GD", N_("Grenada") },
819 {"GE", N_("Georgia") },
820 {"GF", N_("French Guiana") },
821 {"GG", N_("British Channel Isles") },
822 {"GH", N_("Ghana") },
823 {"GI", N_("Gibraltar") },
824 {"GL", N_("Greenland") },
825 {"GM", N_("Gambia") },
826 {"GN", N_("Guinea") },
827 {"GOV", N_("Government") },
828 {"GP", N_("Guadeloupe") },
829 {"GQ", N_("Equatorial Guinea") },
830 {"GR", N_("Greece") },
831 {"GS", N_("S. Georgia and S. Sandwich Isles") },
832 {"GT", N_("Guatemala") },
834 {"GW", N_("Guinea-Bissau") },
835 {"GY", N_("Guyana") },
836 {"HK", N_("Hong Kong") },
837 {"HM", N_("Heard and McDonald Islands") },
838 {"HN", N_("Honduras") },
839 {"HR", N_("Croatia") },
840 {"HT", N_("Haiti") },
841 {"HU", N_("Hungary") },
842 {"ID", N_("Indonesia") },
843 {"IE", N_("Ireland") },
844 {"IL", N_("Israel") },
845 {"IM", N_("Isle of Man") },
846 {"IN", N_("India") },
847 {"INFO", N_("Informational") },
848 {"INT", N_("International") },
849 {"IO", N_("British Indian Ocean Territory") },
852 {"IS", N_("Iceland") },
853 {"IT", N_("Italy") },
854 {"JE", N_("Jersey") },
855 {"JM", N_("Jamaica") },
856 {"JO", N_("Jordan") },
857 {"JP", N_("Japan") },
858 {"KE", N_("Kenya") },
859 {"KG", N_("Kyrgyzstan") },
860 {"KH", N_("Cambodia") },
861 {"KI", N_("Kiribati") },
862 {"KM", N_("Comoros") },
863 {"KN", N_("St. Kitts and Nevis") },
864 {"KP", N_("North Korea") },
865 {"KR", N_("South Korea") },
866 {"KW", N_("Kuwait") },
867 {"KY", N_("Cayman Islands") },
868 {"KZ", N_("Kazakhstan") },
870 {"LB", N_("Lebanon") },
871 {"LC", N_("Saint Lucia") },
872 {"LI", N_("Liechtenstein") },
873 {"LK", N_("Sri Lanka") },
874 {"LR", N_("Liberia") },
875 {"LS", N_("Lesotho") },
876 {"LT", N_("Lithuania") },
877 {"LU", N_("Luxembourg") },
878 {"LV", N_("Latvia") },
879 {"LY", N_("Libya") },
880 {"MA", N_("Morocco") },
881 {"MC", N_("Monaco") },
882 {"MD", N_("Moldova") },
883 {"ME", N_("Montenegro") },
884 {"MED", N_("United States Medical") },
885 {"MG", N_("Madagascar") },
886 {"MH", N_("Marshall Islands") },
887 {"MIL", N_("Military") },
888 {"MK", N_("Macedonia") },
890 {"MM", N_("Myanmar") },
891 {"MN", N_("Mongolia") },
892 {"MO", N_("Macau") },
893 {"MP", N_("Northern Mariana Islands") },
894 {"MQ", N_("Martinique") },
895 {"MR", N_("Mauritania") },
896 {"MS", N_("Montserrat") },
897 {"MT", N_("Malta") },
898 {"MU", N_("Mauritius") },
899 {"MV", N_("Maldives") },
900 {"MW", N_("Malawi") },
901 {"MX", N_("Mexico") },
902 {"MY", N_("Malaysia") },
903 {"MZ", N_("Mozambique") },
904 {"NA", N_("Namibia") },
905 {"NC", N_("New Caledonia") },
906 {"NE", N_("Niger") },
907 {"NET", N_("Internic Network") },
908 {"NF", N_("Norfolk Island") },
909 {"NG", N_("Nigeria") },
910 {"NI", N_("Nicaragua") },
911 {"NL", N_("Netherlands") },
912 {"NO", N_("Norway") },
913 {"NP", N_("Nepal") },
914 {"NR", N_("Nauru") },
916 {"NZ", N_("New Zealand") },
918 {"ORG", N_("Internic Non-Profit Organization") },
919 {"PA", N_("Panama") },
921 {"PF", N_("French Polynesia") },
922 {"PG", N_("Papua New Guinea") },
923 {"PH", N_("Philippines") },
924 {"PK", N_("Pakistan") },
925 {"PL", N_("Poland") },
926 {"PM", N_("St. Pierre and Miquelon") },
927 {"PN", N_("Pitcairn") },
928 {"PR", N_("Puerto Rico") },
929 {"PS", N_("Palestinian Territory") },
930 {"PT", N_("Portugal") },
931 {"PW", N_("Palau") },
932 {"PY", N_("Paraguay") },
933 {"QA", N_("Qatar") },
934 {"RE", N_("Reunion") },
935 {"RO", N_("Romania") },
936 {"RPA", N_("Old School ARPAnet") },
937 {"RS", N_("Serbia") },
938 {"RU", N_("Russian Federation") },
939 {"RW", N_("Rwanda") },
940 {"SA", N_("Saudi Arabia") },
941 {"SB", N_("Solomon Islands") },
942 {"SC", N_("Seychelles") },
943 {"SD", N_("Sudan") },
944 {"SE", N_("Sweden") },
945 {"SG", N_("Singapore") },
946 {"SH", N_("St. Helena") },
947 {"SI", N_("Slovenia") },
948 {"SJ", N_("Svalbard and Jan Mayen Islands") },
949 {"SK", N_("Slovakia") },
950 {"SL", N_("Sierra Leone") },
951 {"SM", N_("San Marino") },
952 {"SN", N_("Senegal") },
953 {"SO", N_("Somalia") },
954 {"SR", N_("Suriname") },
955 {"ST", N_("Sao Tome and Principe") },
956 {"SU", N_("Former USSR") },
957 {"SV", N_("El Salvador") },
958 {"SY", N_("Syria") },
959 {"SZ", N_("Swaziland") },
960 {"TC", N_("Turks and Caicos Islands") },
962 {"TF", N_("French Southern Territories") },
964 {"TH", N_("Thailand") },
965 {"TJ", N_("Tajikistan") },
966 {"TK", N_("Tokelau") },
967 {"TL", N_("East Timor") },
968 {"TM", N_("Turkmenistan") },
969 {"TN", N_("Tunisia") },
970 {"TO", N_("Tonga") },
971 {"TP", N_("East Timor") },
972 {"TR", N_("Turkey") },
973 {"TT", N_("Trinidad and Tobago") },
974 {"TV", N_("Tuvalu") },
975 {"TW", N_("Taiwan") },
976 {"TZ", N_("Tanzania") },
977 {"UA", N_("Ukraine") },
978 {"UG", N_("Uganda") },
979 {"UK", N_("United Kingdom") },
980 {"US", N_("United States of America") },
981 {"UY", N_("Uruguay") },
982 {"UZ", N_("Uzbekistan") },
983 {"VA", N_("Vatican City State") },
984 {"VC", N_("St. Vincent and the Grenadines") },
985 {"VE", N_("Venezuela") },
986 {"VG", N_("British Virgin Islands") },
987 {"VI", N_("US Virgin Islands") },
988 {"VN", N_("Vietnam") },
989 {"VU", N_("Vanuatu") },
990 {"WF", N_("Wallis and Futuna Islands") },
991 {"WS", N_("Samoa") },
992 {"YE", N_("Yemen") },
993 {"YT", N_("Mayotte") },
994 {"YU", N_("Yugoslavia") },
995 {"ZA", N_("South Africa") },
996 {"ZM", N_("Zambia") },
997 {"ZW", N_("Zimbabwe") },
1001 country (char *hostname
)
1006 if (!hostname
|| !*hostname
|| isdigit ((unsigned char) hostname
[strlen (hostname
) - 1]))
1007 return _("Unknown");
1008 if ((p
= strrchr (hostname
, '.')))
1013 dom
= bsearch (p
, domain
, sizeof (domain
) / sizeof (domain_t
),
1014 sizeof (domain_t
), country_compare
);
1017 return _("Unknown");
1019 return _(dom
->country
);
1023 country_search (char *pattern
, void *ud
, void (*print
)(void *, char *, ...))
1025 const domain_t
*dom
;
1028 for (i
= 0; i
< sizeof (domain
) / sizeof (domain_t
); i
++)
1031 if (match (pattern
, dom
->country
) || match (pattern
, _(dom
->country
)))
1033 print (ud
, "%s = %s\n", dom
->code
, _(dom
->country
));
1038 /* I think gnome1.0.x isn't necessarily linked against popt, ah well! */
1039 /* !!! For now use this inlined function, or it would break fe-text building */
1040 /* .... will find a better solution later. */
1041 /*#ifndef USE_GNOME*/
1043 /* this is taken from gnome-libs 1.2.4 */
1044 #define POPT_ARGV_ARRAY_GROW_DELTA 5
1046 int my_poptParseArgvString(const char * s
, int * argcPtr
, char *** argvPtr
) {
1047 char * buf
, * bufStart
, * dst
;
1050 int argvAlloced
= POPT_ARGV_ARRAY_GROW_DELTA
;
1051 char ** argv
= malloc(sizeof(*argv
) * argvAlloced
);
1052 const char ** argv2
;
1056 buflen
= strlen(s
) + 1;
1057 /* bufStart = buf = alloca(buflen);*/
1058 bufStart
= buf
= malloc (buflen
);
1059 memset(buf
, '\0', buflen
);
1065 if (quote
== *src
) {
1075 if (*src
!= quote
) *buf
++ = '\\';
1078 /*} else if (isspace((unsigned char) *src)) {*/
1079 } else if (*src
== ' ') {
1082 if (argc
== argvAlloced
) {
1083 argvAlloced
+= POPT_ARGV_ARRAY_GROW_DELTA
;
1084 argv
= realloc(argv
, sizeof(*argv
) * argvAlloced
);
1088 } else switch (*src
) {
1108 if (strlen(argv
[argc
])) {
1112 dst
= malloc((argc
+ 1) * sizeof(*argv
) + (buf
- bufStart
));
1113 argv2
= (void *) dst
;
1114 dst
+= (argc
+ 1) * sizeof(*argv
);
1115 memcpy((void *)argv2
, argv
, argc
* sizeof(*argv
));
1117 memcpy(dst
, bufStart
, buf
- bufStart
);
1119 for (i
= 0; i
< argc
; i
++) {
1120 argv2
[i
] = dst
+ (argv
[i
] - bufStart
);
1125 *argvPtr
= (char **)argv2
; /* XXX don't change the API */
1134 util_exec (const char *cmd
)
1141 if (my_poptParseArgvString (cmd
, &argc
, &argv
) != 0)
1149 /* Now close all open file descriptors except stdin, stdout and stderr */
1150 for (fd
= 3; fd
< 1024; fd
++) close(fd
);
1151 execvp (argv
[0], argv
);
1161 util_execv (char * const argv
[])
1170 /* Now close all open file descriptors except stdin, stdout and stderr */
1171 for (fd
= 3; fd
< 1024; fd
++) close(fd
);
1172 execv (argv
[0], argv
);
1181 make_ping_time (void)
1183 struct timeval timev
;
1184 gettimeofday (&timev
, 0);
1185 return (timev
.tv_sec
- 50000) * 1000000 + timev
.tv_usec
;
1189 /************************************************************************
1190 * This technique was borrowed in part from the source code to
1191 * ircd-hybrid-5.3 to implement case-insensitive string matches which
1192 * are fully compliant with Section 2.2 of RFC 1459, the copyright
1193 * of that code being (C) 1990 Jarkko Oikarinen and under the GPL.
1195 * A special thanks goes to Mr. Okarinen for being the one person who
1196 * seems to have ever noticed this section in the original RFC and
1197 * written code for it. Shame on all the rest of you (myself included).
1199 * --+ Dagmar d'Surreal
1203 rfc_casecmp (const char *s1
, const char *s2
)
1205 register unsigned char *str1
= (unsigned char *) s1
;
1206 register unsigned char *str2
= (unsigned char *) s2
;
1209 while ((res
= rfc_tolower (*str1
) - rfc_tolower (*str2
)) == 0)
1220 rfc_ncasecmp (char *str1
, char *str2
, int n
)
1222 register unsigned char *s1
= (unsigned char *) str1
;
1223 register unsigned char *s2
= (unsigned char *) str2
;
1226 while ((res
= rfc_tolower (*s1
) - rfc_tolower (*s2
)) == 0)
1231 if (n
== 0 || (*s1
== '\0' && *s2
== '\0'))
1237 const unsigned char rfc_tolowertab
[] =
1238 { 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
1239 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
1240 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
1242 ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
1243 '*', '+', ',', '-', '.', '/',
1244 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1245 ':', ';', '<', '=', '>', '?',
1246 '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
1247 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
1248 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
1250 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
1251 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
1252 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
1254 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
1255 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1256 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
1257 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1258 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
1259 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
1260 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
1261 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1262 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
1263 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1264 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
1265 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1266 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
1267 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
1268 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
1269 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1272 /*static unsigned char touppertab[] =
1273 { 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
1274 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
1275 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
1277 ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
1278 '*', '+', ',', '-', '.', '/',
1279 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1280 ':', ';', '<', '=', '>', '?',
1281 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
1282 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
1283 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
1285 '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
1286 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
1287 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
1289 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
1290 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1291 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
1292 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1293 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
1294 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
1295 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
1296 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1297 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
1298 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1299 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
1300 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1301 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
1302 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
1303 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
1304 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1308 rename_utf8 (char *oldname, char *newname)
1313 fso = xchat_filename_from_utf8 (oldname, -1, 0, 0, 0);
1316 fsn = xchat_filename_from_utf8 (newname, -1, 0, 0, 0);
1323 res = rename (fso, fsn);
1332 unlink_utf8 (char *fname)
1337 fs = xchat_filename_from_utf8 (fname, -1, 0, 0, 0);
1347 file_exists_utf8 (char *fname
)
1352 fs
= xchat_filename_from_utf8 (fname
, -1, 0, 0, 0);
1356 res
= access (fs
, F_OK
);
1364 copy_file (char *dl_src
, char *dl_dest
, int permissions
) /* FS encoding */
1366 int tmp_src
, tmp_dest
;
1367 gboolean ok
= FALSE
;
1369 int return_tmp
, return_tmp2
;
1371 if ((tmp_src
= open (dl_src
, O_RDONLY
| OFLAGS
)) == -1)
1373 fprintf (stderr
, "Unable to open() file '%s' (%s) !", dl_src
,
1379 open (dl_dest
, O_WRONLY
| O_CREAT
| O_TRUNC
| OFLAGS
, permissions
)) < 0)
1382 fprintf (stderr
, "Unable to create file '%s' (%s) !", dl_src
,
1389 return_tmp
= read (tmp_src
, dl_tmp
, sizeof (dl_tmp
));
1399 fprintf (stderr
, "download_move_to_completed_dir(): "
1400 "error reading while moving file to save directory (%s)",
1405 return_tmp2
= write (tmp_dest
, dl_tmp
, return_tmp
);
1407 if (return_tmp2
< 0)
1409 fprintf (stderr
, "download_move_to_completed_dir(): "
1410 "error writing while moving file to save directory (%s)",
1415 if (return_tmp
< sizeof (dl_tmp
))
1427 /* Takes care of moving a file from a temporary download location to a completed location. Now in UTF-8. */
1429 move_file_utf8 (char *src_dir
, char *dst_dir
, char *fname
, int dccpermissions
)
1434 char *src_fs
; /* FileSystem encoding */
1437 /* if dcc_dir and dcc_completed_dir are the same then we are done */
1438 if (0 == strcmp (src_dir
, dst_dir
) ||
1440 return; /* Already in "completed dir" */
1442 snprintf (src
, sizeof (src
), "%s/%s", src_dir
, fname
);
1443 snprintf (dst
, sizeof (dst
), "%s/%s", dst_dir
, fname
);
1445 /* already exists in completed dir? Append a number */
1446 if (file_exists_utf8 (dst
))
1450 snprintf (dst
, sizeof (dst
), "%s/%s.%d", dst_dir
, fname
, i
);
1451 if (!file_exists_utf8 (dst
))
1456 /* convert UTF-8 to filesystem encoding */
1457 src_fs
= xchat_filename_from_utf8 (src
, -1, 0, 0, 0);
1460 dst_fs
= xchat_filename_from_utf8 (dst
, -1, 0, 0, 0);
1467 /* first try a simple rename move */
1468 res
= rename (src_fs
, dst_fs
);
1470 if (res
== -1 && (errno
== EXDEV
|| errno
== EPERM
))
1472 /* link failed because either the two paths aren't on the */
1473 /* same filesystem or the filesystem doesn't support hard */
1474 /* links, so we have to do a copy. */
1475 if (copy_file (src_fs
, dst_fs
, dccpermissions
))
1484 mkdir_utf8 (char *dir
)
1488 dir
= xchat_filename_from_utf8 (dir
, -1, 0, 0, 0);
1492 ret
= mkdir (dir
, S_IRUSR
| S_IWUSR
| S_IXUSR
);
1498 /* separates a string according to a 'sep' char, then calls the callback
1499 function for each token found */
1502 token_foreach (char *str
, char sep
,
1503 int (*callback
) (char *str
, void *ud
), void *ud
)
1505 char t
, *start
= str
;
1509 if (*str
== sep
|| *str
== 0)
1513 if (callback (start
, ud
) < 1)
1527 /* chars $00-$7f can never be embedded in utf-8 */
1535 /* 31 bit string hash functions */
1538 str_hash (const char *key
)
1540 const char *p
= key
;
1544 for (p
+= 1; *p
!= '\0'; p
++)
1545 h
= (h
<< 5) - h
+ *p
;
1551 str_ihash (const unsigned char *key
)
1553 const char *p
= key
;
1554 guint32 h
= rfc_tolowertab
[(guint
)*p
];
1557 for (p
+= 1; *p
!= '\0'; p
++)
1558 h
= (h
<< 5) - h
+ rfc_tolowertab
[(guint
)*p
];
1563 /* features: 1. "src" must be valid, NULL terminated UTF-8 */
1564 /* 2. "dest" will be left with valid UTF-8 - no partial chars! */
1567 safe_strcpy (char *dest
, const char *src
, int bytes_left
)
1573 mbl
= g_utf8_skip
[*((unsigned char *)src
)];
1575 if (bytes_left
< (mbl
+ 1)) /* can't fit with NULL? */
1581 if (mbl
== 1) /* one byte char */
1585 break; /* it all fit */
1590 else /* multibyte char */
1592 memcpy (dest
, src
, mbl
);
1601 encode_sasl_pass_plain (char *user
, char *pass
)
1607 /* we can't call strlen() directly on buffer thanks to the atrocious \0 characters it requires */
1608 authlen
= strlen (user
) * 2 + 2 + strlen (pass
);
1609 buffer
= g_strdup_printf ("%s%c%s%c%s", user
, '\0', user
, '\0', pass
);
1610 encoded
= g_base64_encode ((unsigned char*) buffer
, authlen
);
1617 /* Adapted from ZNC's SASL module */
1620 parse_dh (char *str
, DH
**dh_out
, unsigned char **secret_out
, int *keysize_out
)
1623 guchar
*data
, *decoded_data
;
1632 data
= decoded_data
= g_base64_decode (str
, &data_len
);
1637 memcpy (&size16
, data
, sizeof(size16
));
1638 size
= ntohs (size16
);
1642 if (size
> data_len
)
1645 dh
->p
= BN_bin2bn (data
, size
, NULL
);
1652 memcpy (&size16
, data
, sizeof(size16
));
1653 size
= ntohs (size16
);
1657 if (size
> data_len
)
1660 dh
->g
= BN_bin2bn (data
, size
, NULL
);
1667 memcpy (&size16
, data
, sizeof(size16
));
1668 size
= ntohs(size16
);
1672 pubkey
= BN_bin2bn (data
, size
, NULL
);
1673 if (!(DH_generate_key (dh
)))
1676 secret
= (unsigned char*)malloc (DH_size(dh
));
1677 key_size
= DH_compute_key (secret
, pubkey
, dh
);
1681 g_free (decoded_data
);
1684 *secret_out
= secret
;
1685 *keysize_out
= key_size
;
1690 g_free (decoded_data
);
1695 encode_sasl_pass_blowfish (char *user
, char *pass
, char *data
)
1698 char *response
, *ret
;
1699 unsigned char *secret
;
1700 unsigned char *encrypted_pass
;
1703 int key_size
, length
;
1704 int pass_len
= strlen (pass
) + (8 - (strlen (pass
) % 8));
1705 int user_len
= strlen (user
);
1707 char *in_ptr
, *out_ptr
;
1709 if (!parse_dh (data
, &dh
, &secret
, &key_size
))
1711 BF_set_key (&key
, key_size
, secret
);
1713 encrypted_pass
= calloc (pass_len
, 1);
1714 plain_pass
= malloc (pass_len
);
1715 if(!encrypted_pass
|| !plain_pass
)
1717 strncpy (plain_pass
, pass
, pass_len
); /* yes, we really want strncpy here */
1718 out_ptr
= (char*)encrypted_pass
;
1719 in_ptr
= (char*)plain_pass
;
1721 for (length
= pass_len
; length
; length
-= 8, in_ptr
+= 8, out_ptr
+= 8)
1722 BF_ecb_encrypt ((unsigned char*)in_ptr
, (unsigned char*)out_ptr
, &key
, BF_ENCRYPT
);
1724 /* Create response */
1725 length
= 2 + BN_num_bytes (dh
->pub_key
) + pass_len
+ user_len
+ 1;
1726 response
= (char*)malloc (length
);
1730 size16
= htons ((guint16
)BN_num_bytes (dh
->pub_key
));
1731 memcpy (out_ptr
, &size16
, sizeof(size16
));
1733 BN_bn2bin (dh
->pub_key
, (guchar
*)out_ptr
);
1734 out_ptr
+= BN_num_bytes (dh
->pub_key
);
1737 memcpy (out_ptr
, user
, user_len
+ 1);
1738 out_ptr
+= user_len
+ 1;
1741 memcpy (out_ptr
, encrypted_pass
, pass_len
);
1743 ret
= g_base64_encode ((const guchar
*)response
, length
);
1747 free (encrypted_pass
);
1755 encode_sasl_pass_aes (char *user
, char *pass
, char *data
)
1759 char *response
= NULL
;
1760 char *out_ptr
, *ret
= NULL
;
1761 unsigned char *secret
, *ptr
;
1762 unsigned char *encrypted_userpass
, *plain_userpass
;
1763 int key_size
, length
;
1765 unsigned char iv
[16], iv_copy
[16];
1766 int user_len
= strlen (user
) + 1;
1767 int pass_len
= strlen (pass
) + 1;
1768 int len
= user_len
+ pass_len
;
1769 int padlen
= 16 - (len
% 16);
1770 int userpass_len
= len
+ padlen
;
1772 if (!parse_dh (data
, &dh
, &secret
, &key_size
))
1775 encrypted_userpass
= (guchar
*)malloc (userpass_len
);
1776 memset (encrypted_userpass
, 0, userpass_len
);
1777 plain_userpass
= (guchar
*)malloc (userpass_len
);
1778 memset (plain_userpass
, 0, userpass_len
);
1780 /* create message */
1781 /* format of: <username>\0<password>\0<padding> */
1782 ptr
= plain_userpass
;
1783 memcpy (ptr
, user
, user_len
);
1785 memcpy (ptr
, pass
, pass_len
);
1790 unsigned char randbytes
[16];
1791 if (!RAND_bytes (randbytes
, padlen
))
1794 memcpy (ptr
, randbytes
, padlen
);
1797 if (!RAND_bytes (iv
, sizeof (iv
)))
1800 memcpy (iv_copy
, iv
, sizeof(iv
));
1803 AES_set_encrypt_key (secret
, key_size
* 8, &key
);
1804 AES_cbc_encrypt(plain_userpass
, encrypted_userpass
, userpass_len
, &key
, iv_copy
, AES_ENCRYPT
);
1806 /* Create response */
1807 /* format of: <size pubkey><pubkey><iv (always 16 bytes)><ciphertext> */
1808 length
= 2 + key_size
+ sizeof(iv
) + userpass_len
;
1809 response
= (char*)malloc (length
);
1813 size16
= htons ((guint16
)key_size
);
1814 memcpy (out_ptr
, &size16
, sizeof(size16
));
1816 BN_bn2bin (dh
->pub_key
, (guchar
*)out_ptr
);
1817 out_ptr
+= key_size
;
1820 memcpy (out_ptr
, iv
, sizeof(iv
));
1821 out_ptr
+= sizeof(iv
);
1824 memcpy (out_ptr
, encrypted_userpass
, userpass_len
);
1826 ret
= g_base64_encode ((const guchar
*)response
, length
);
1830 free (plain_userpass
);
1831 free (encrypted_userpass
);
1842 str_sha256hash (char *string
)
1845 unsigned char hash
[SHA256_DIGEST_LENGTH
];
1846 char buf
[SHA256_DIGEST_LENGTH
* 2 + 1]; /* 64 digit hash + '\0' */
1849 SHA256_Init (&sha256
);
1850 SHA256_Update (&sha256
, string
, strlen (string
));
1851 SHA256_Final (hash
, &sha256
);
1853 for (i
= 0; i
< SHA256_DIGEST_LENGTH
; i
++)
1855 sprintf (buf
+ (i
* 2), "%02x", hash
[i
]);
1858 buf
[SHA256_DIGEST_LENGTH
* 2] = 0;
1860 return g_strdup (buf
);
1864 * \brief Generate CHALLENGEAUTH response for QuakeNet login.
1866 * \param username QuakeNet user name
1867 * \param password password for the user
1868 * \param challenge the CHALLENGE response we got from Q
1870 * After a successful connection to QuakeNet a CHALLENGE is requested from Q.
1871 * Generate the CHALLENGEAUTH response from this CHALLENGE and our user
1872 * credentials as per the
1873 * <a href="http://www.quakenet.org/development/challengeauth">CHALLENGEAUTH</a>
1874 * docs. As for using OpenSSL HMAC, see
1875 * <a href="http://www.askyb.com/cpp/openssl-hmac-hasing-example-in-cpp/">example 1</a>,
1876 * <a href="http://stackoverflow.com/questions/242665/understanding-engine-initialization-in-openssl">example 2</a>.
1879 challengeauth_response (char *username
, char *password
, char *challenge
)
1887 unsigned char *digest
;
1888 GString
*buf
= g_string_new_len (NULL
, SHA256_DIGEST_LENGTH
* 2);
1890 user
= g_strdup (username
);
1891 *user
= rfc_tolower (*username
); /* convert username to lowercase as per the RFC*/
1893 pass
= g_strndup (password
, 10); /* truncate to 10 characters */
1894 passhash
= str_sha256hash (pass
);
1897 key
= g_strdup_printf ("%s:%s", user
, passhash
);
1901 keyhash
= str_sha256hash (key
);
1904 digest
= HMAC (EVP_sha256 (), keyhash
, strlen (keyhash
), (unsigned char *) challenge
, strlen (challenge
), NULL
, NULL
);
1907 for (i
= 0; i
< SHA256_DIGEST_LENGTH
; i
++)
1909 g_string_append_printf (buf
, "%02x", (unsigned int) digest
[i
]);
1912 digest
= (unsigned char *) g_string_free (buf
, FALSE
);
1914 return (char *) digest
;