1. #!/usr/bin/perl
2. ######################################
3. ## Coded by Douglas[at]WeakNetLabs[dot]com
4. ## Coded by Chartreuse[at]WeakNetLabs[dot]com
5. #####################################
6. # TODO List: (Add to when new features are wanted with priorities 0-9 where 0 is urgent)
7. # + -7- Create configuration file code and store the environment there to be loaded
8. # + -6- Create a Help File/Help Page to display for command help
9. # + -3- Create more commands and populate them out
10. # + -9- Trap Arrow keys and implement functions to do scrollback
11. # + -5- Remove system call's in favor of modules -- system calls reduce portability
12. #
13. #
14. #
15. #
16. #
17. #####################################
18. # Change Log:
19. # [18/05/10 Chartreuse] Recoded Trevelyn's original code and added my own
20. # [19/05/10 Chartreuse] Added in Trevelyn's new code for mysql and such
21. # Made Help function print list of valid commands
22. # Moved parsing user input to it's own function
23. # Added support for command alias's
24. #
25. ##
26. use strict;
27. use warnings;
28.
29. #####################################
30. # Load up Modules
31. ##
32. use Cwd;
33. use Term::ANSIColor;
34. use File::Spec;
35. use POSIX;
36. use Term::Cap;
37.
38.
39. #####################################
40. # Pre-set Environment variables
41. ## TODO: Move to configuration file (.celeritasrc) and load on startup
42. my $hostname = "celeritas";
43. my $PS1 = colored (getlogin() . "\@$hostname", "bold green") . colored (" " . getWorkingDirectory() . "%", "bold blue") . " ";
44. my $version = "0.1.1-ALPHA";
45.
46. ####################################
47. # Global Variables -- Avoid Creating these
48. ## TODO: Find other solutions rather than these
49. my $term; # Needed for term::cap
50. my $termios = new POSIX::Termios; # Needed for term::cap
51. my $iAmAlive = 1; # Clean exit flag
52.
53. my $db = "";
54. my $usr = "";
55. my $col = 0;
56. my $pass = "";
57.
58. my @validCommands = qw /exit echo sys help clear mysql set use show/; # List of valid commands that can be symbolically called
59. my %commandAlias = ( # Hash of alias's, key = alias name, value = command name
60. "usedb" => "use"
61. );
62.
63. ####################################
64. ##### ENTRY POINT - Begin Here #####
65. ####################################
66. initialSetup();
67. mainLoop();
68. cleanUpAndQuit();
69. ###################################
70. ######### END ENTRY POINT #########
71. ###################################
72.
73.
74. ###################################
75. # Subroutines Here
76. ##
77. ### initialSetup() - Preconfigure everything before entering mainLoop()
78. # TODO: Unknown
79. sub initialSetup
80. {
81. ## Stuff needed for Term::Cap
82.
83. # General terminal line I/O
84. $termios->getattr;
85. # Extract the entry of the terminal type
86. $term = Term::Cap->Tgetent( { TERM => undef, OSPEED => $termios->getospeed } );
87.
88. return;
89. }
90. ### mainLoop() - Program Flow and Logic Here ###
91. # TODO: Unknown
92. sub mainLoop
93. {
94. my $returnValue=0;
95. while($iAmAlive) ## Logic Loop while we have not been told to exit nicely
96. {
97. printPrompt(); # Show us a prompt
98. parseUserInput();
99.
100. }
101.
102. return;
103. }
104. sub parseUserInput
105. {
106. chomp( my $userCommand = <STDIN> ); # Set $userCommand with user input and clean off any trailing newlines
107. $userCommand =~ /^(\S+)\s?(.*)/; # Return all characters up till first space and everything after first space
108.
109. my $commandName = $1;
110. my $commandArguments = $2;
111.
112. if(!( grep {$_ eq lc($1)} @validCommands))
113. {
114. if( exists $commandAlias{$1} ) # Check if we are dealing with a command alias
115. {
116. no strict 'refs'; # Should we even be doing the symbolic-references in the first place?
117.
118. return &{lc($commandAlias{$1} . "_cmd")}($2); # Does the postfix protection make this safe enough?
119. }
120. else
121. {
122. print colored("Celeritas:", "bold red") . colored(" $1","bold") . " command not understood\n";
123. return 0;
124. }
125. }
126. else
127. {
128. no strict 'refs'; # Should we even be doing the symbolic-references in the first place?
129. $commandName .= "_cmd"; # Append postfix to entered command and call it
130. return &{lc($commandName)}($2); # Does the postfix protection make this safe enough?
131. }
132. return 0;
133. }
134. ### printPrompt() - Prints the prompt ($PS1) to STDIN
135. # TODO: Unknown
136. sub printPrompt
137. {
138. print $PS1; # Just print out the prompt string for now
139. return;
140. }
141.
142. ### getWorkingDirectory() - Returns the current working directory without the full path
143. # TODO: Unknown
144. sub getWorkingDirectory
145. {
146. my @dirs = File::Spec->splitdir( Cwd::cwd() ); # Split the Current working path
147. return $dirs[$#dirs]; # Return the last element, (The current directory)
148. }
149.
150. ### cleanUpAndQuit() - Clean up all we've done, prepare to quit, and quit
151. # TODO: Unknown
152. sub cleanUpAndQuit
153. {
154. print "\n"; # Give shell some breathing room before leaving
155. exit(0);
156. }
157.
158. ####################################
159. # Celeritas Commands Below
160. ## TODO: Populate Commands
161.
162. ### exit_cmd - Command to nicely exit back to the shell
163. # TODO: Unknown
164. sub exit_cmd
165. {
166. print "Now Exiting... See you later :)\n";
167. $iAmAlive = 0;
168.
169. return;
170. }
171. ### echo_cmd - Command to echo arguments out to STDOUT
172. # TODO: Possible Input Protection? Required?
173. sub echo_cmd
174. {
175. my ($input) = @_;
176. print "$input\n";
177.
178. return;
179. }
180. ### sys_cmd - Run command through the host shell
181. # TODO: Reimplement Trevelyn's Backref the REGEX code into a subroutine
182. sub sys_cmd
183. {
184. # Trevelyn's Backreference the REGEX Code
185. my ($input) = @_;
186. my @split;
187. if ($input =~ /\\-[0-9]/) {
188. @split = split(/\)/, $input);
189. foreach (@split) {
190. $_ =~ s/.*\(//g;
191. }
192. }
193. my $n = 0;
194. foreach (@split) {
195. $n++;
196. $input =~ s/\\-$n/\($_\)/g;
197. }
198.
199. system($input); # Run the command
200. print "Command was $input\n";
201. return;
202. }
203. ### help_cmd - Display help pages to user
204. # TODO: Create Help Menu
205. sub help_cmd
206. {
207. print "Help\n";
208. print "-----------------\n";
209. print "Valid Commands: \n";
210. print join(" ", @validCommands) . "\n";
211. print "Help not yet fully implemented... Sorry :(\n";
212.
213. return;
214. }
215. ### clear_cmd - Clears the screen
216. # TODO: Unknown
217. sub clear_cmd
218. {
219. print $term->Tputs('cl');
220. return;
221. }
222. ### mysql_cmd - Run mysql
223. # TODO: Use Modules instead of system command?
224. sub mysql_cmd {
225. my @split_cmd = split(" ", shift);
226. if (@split_cmd)
227. {
228. my ($what,$table,$regexp);
229. my $n = 0;
230. foreach (@split_cmd)
231. {
232. if ($_ =~ /select/i) { $what = $split_cmd[($n)]; }
233. if ($_ =~ /from/i) { $table = $split_cmd[($n)]; }
234. if ($_ =~ /REGEXP/) { $regexp = $split_cmd[($n)]; }
235. $n++;
236. }
237. # slurp all results line x line into array @lines:
238. ## SYSTEM COMMAND, perhaps use the MySQL module? ##
239. my @lines = `mysql -t -e \'select $what from $table\' $db --password=$pass --user=$usr`;
240. # get column of target for "where $something regexp..."
241.
242. my $g = 0;
243. print $lines[0] . $lines[1] . $lines[2];
244.
245. foreach( $lines[1] )
246. {
247. if ($_ =~ /where/i)
248. {
249. $col = ($g + 1); ## Changed from my $col to $col, it's already a global var, did you mean to locally scope it to inside this if statement only?
250. last();
251. } $g++;
252. }
253.
254. my $t = $#lines;
255. foreach(@lines[3..$t])
256. {
257. my @split_lines = split(/" "/, $_);
258. # Here it is, if it's here, it gets printed:
259. if ($split_lines[$col] =~ /$regexp/)
260. {
261. chomp $_;
262. print "$_\n";
263. print $lines[0];
264. }
265. }
266. #print "The command was: select " . $what . " from " . " $table " . " where column " . $something . " had a regexp match of " . $regexp . "\n";
267. }
268. return;
269. }
270. ### set_cmd - Set variables for built in commands
271. # TODO: Add more? Maybe make these like environment variables
272. # and use a symbolic reference to store them as
273. # varname_env and make them accessable in commands
274. # and regex
275. sub set_cmd {
276. my @split_cmd = split(" ", shift);
277. if (@split_cmd)
278. {
279. if ($split_cmd[0] eq 'db' or $split_cmd[0] eq 'database') {
280. print "Database: ";
281. $db = <STDIN>;
282. chomp $db;
283. return;
284. }
285. if ($split_cmd[0] eq 'pass' or $split_cmd[0] eq 'passwd') {
286. print "Password: ";
287. system "stty -echo"; ## Use Term::Cap module to remove the need for system call?
288. $pass = <STDIN>;
289. chomp $pass;
290. system "stty echo"; ## Use Term::Cap module to remove the need for system call?
291. print "\n";
292. return;
293. }
294. if ($split_cmd[0] eq 'usr' or $split_cmd[0] eq 'user') {
295. print "Username: ";
296. $usr = <STDIN>;
297. chomp $usr;
298. return;
299. }
300. }
301. return;
302. }
303. ### use_cmd - Set which database we are using
304. # Alias's: usedb
305. # TODO: Unknown
306. sub use_cmd {
307. my @split_cmd = split(" ", shift);
308. if (@split_cmd)
309. {
310. if ($split_cmd[0] eq '') {
311. print "Invalid name for database.\n";
312. return 0;
313. }
314. else {
315. $db = $split_cmd[0];
316. print "Database successfully changed to " . $db . "\n";
317. return;
318. }
319. }
320. }
321. ### show_cmd - Show all variables for built in commands
322. # TODO: Same as set_cmd, possibly use an env variables type setup
323. sub show_cmd {
324. my @split_cmd = split(" ", shift);
325. if (@split_cmd)
326. {
327. if ($split_cmd[0] eq 'db' or $split_cmd[0] eq 'database' or $split_cmd[0] eq 'dbase') {
328. print $db . "\n";
329. return;
330. }
331. if ($split_cmd[0] eq 'user' or $split_cmd[0] eq 'usr' or $split_cmd[0] eq 'who') {
332. print $usr . "\n";
333. return;
334. }
335. if ($split_cmd[0] eq 'version' or $split_cmd[0] eq 'v' or $split_cmd[0] eq 'V') {
336. print $version . "\n";
337. return;
338. }
339. if ($split_cmd[0] eq 'help') {
340. help();
341. }
342. else {
343. print "Error: " . $split_cmd[0] . " not yet implemented for command: \"show\"\n";
344. return;
345. }
346. }
347. }