1 //
2 // aegis - project change supervisor
3 // Copyright (C) 2006-2008, 2010, 2012 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or (at
8 // your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18
19 #include <common/ac/assert.h>
20 #include <common/ac/ctype.h>
21 #include <common/ac/string.h>
22
23 #include <libaegis/attribute.h>
24 #include <libaegis/change/file.h>
25 #include <libaegis/fstate.fmtgen.h>
26 #include <libaegis/input/file.h>
27 #include <libaegis/os.h>
28 #include <libaegis/sub.h>
29
30 #include <aede-policy/validation/files/printable.h>
31
32
~validation_files_printable()33 validation_files_printable::~validation_files_printable()
34 {
35 }
36
37
validation_files_printable()38 validation_files_printable::validation_files_printable()
39 {
40 }
41
42
43 validation::pointer
create(void)44 validation_files_printable::create(void)
45 {
46 return pointer(new validation_files_printable());
47 }
48
49
50 bool
check_binaries() const51 validation_files_printable::check_binaries()
52 const
53 {
54 return false;
55 }
56
57
58 static bool
international_character_set(fstate_src_ty * src)59 international_character_set(fstate_src_ty *src)
60 {
61 //
62 // If the content-type attribute doesn't exist, or no character set
63 // is specified by the content-type, plain ascii is assumed.
64 //
65 attributes_ty *ap = attributes_list_find(src->attribute, "content-type");
66 if (!ap || !ap->value)
67 return false;
68 const char *cp = strstr(ap->value->str_text, "charset=");
69 if (!cp)
70 return false;
71 cp += 8;
72 return (0 != strcmp(cp, "ascii") && 0 != strcmp(cp, "us-ascii"));
73 }
74
75
76 bool
check(change::pointer cp,fstate_src_ty * src)77 validation_files_printable::check(change::pointer cp, fstate_src_ty *src)
78 {
79 //
80 // Note: we return true if the file is acceptable to the policy
81 // (i.e. has no unprintable characters). We return false if the
82 // file is unacceptable.
83 //
84 nstring path(cp->file_path(src));
85 assert(!path.empty());
86 if (path.empty())
87 return true;
88
89 os_become_orig();
90 bool result = true;
91 input ip = input_file_open(path);
92 if
93 (
94 nstring(src->file_name).ends_with(".po")
95 ||
96 international_character_set(src)
97 )
98 {
99 //
100 // An obvious exception is the message translation files, which
101 // are supposed to contain character sets other than ASCII.
102 //
103 for (;;)
104 {
105 int c = ip->getch();
106 if (c < 0)
107 break;
108 if (c == 0)
109 {
110 sub_context_ty sc;
111 sc.var_set_string("File_Name", src->file_name);
112 change_error(cp, &sc, i18n("$filename: is binary"));
113 result = false;
114 break;
115 }
116 }
117 }
118 else
119 {
120 int line_number = 1;
121 for (;;)
122 {
123 int c = ip->getch();
124 if (c < 0)
125 break;
126 if (c == 0)
127 {
128 sub_context_ty sc;
129 sc.var_set_string("File_Name", src->file_name);
130 change_error(cp, &sc, i18n("$filename: is binary"));
131 result = false;
132 break;
133 }
134 unsigned char uc = c;
135 // Using the "C" locale.
136 if (!isprint(uc) && !isspace(uc))
137 {
138 sub_context_ty sc;
139 sc.var_set_string("File_Name", src->file_name);
140 sc.var_set_long("Number", line_number);
141 sc.var_optional("Number");
142 change_error(cp, &sc, i18n("$filename: is unprintable"));
143 result = false;
144 break;
145 }
146 if (c == '\n')
147 ++line_number;
148 }
149 }
150 ip.close();
151 os_become_undo();
152 return result;
153 }
154
155
156 // vim: set ts=8 sw=4 et :
157