/[AnywhereTS-MSSQL]/trunk/TSAdminTool/ProSupport.cs
ViewVC logotype

Contents of /trunk/TSAdminTool/ProSupport.cs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 16 - (show annotations) (download)
Wed Jul 11 16:36:27 2012 UTC (7 years, 7 months ago) by william
File size: 27859 byte(s)
ProSupport.InitDatabase(): don't overwrite the application settings for connection string

1
2 using System;
3 using System.Collections;
4 using System.Collections.Generic;
5 using System.Text;
6 using System.Windows.Forms;
7 using System.Globalization;
8 using System.Data;
9 using System.Security.AccessControl;
10 using System.Security.Principal;
11 using System.IO;
12 using System.Management;
13 using System.Net;
14
15 // Support class for the AnywhereTS version. This file should only be included in the Pro version.
16 namespace AnywhereTS
17 {
18 public static class ProSupport
19 {
20 // File names
21 public const string strHostsFilename = "hosts"; // The name of the thin clients host file.
22 public const string strNetworkConfigFilename = "network"; // Name of the Thinstation common config file in the TFTP root directory.
23 public const string strDatabaseFilename = "ats.mdf"; // Name of the AnywhereTS SQL express database file.
24 public const string strDatabaseFilename2 = "ats_log.ldf"; // Name of the AnywhereTS SQL express database log file.
25
26 // Registry keys
27 public const string strRegTFTP_root = "TFTP_root"; // Reg key for TFTP root directory in database
28 public const string strRegDatabaseDir = "DatabaseDir"; // Reg key for database directory
29 public const string strRegDatabaseServer = "DatabaseServer"; // Reg key for database server
30 public const string strRegDestDir = "DestDir"; // Reg key for Destination directory, used in unmanged mode..
31
32 // Database constants
33 public const string DEFAULT_RECORD_MAC = "Default "; // Phony MAC address (12 chars) used to identify the client record that contains the default settings for all new clients
34
35 // Database variables
36 public static atsDataSetTableAdapters.ClientTableAdapter clientTableAdapter; // The AnywhereTS application data adapter for the clients table. Only this adapter should be used.
37 public static atsDataSetTableAdapters.TftpServerTableAdapter tftpServerTableAdapter; // The AnywhereTS application data adapter for the TFTP servers table. Only this adapter should be used.
38 public static atsDataSetTableAdapters.TerminalServerTableAdapter terminalServerTableAdapter; // The AnywhereTS application data adapter for the terminal servers table. Only this adapter should be used.
39 public static atsDataSetTableAdapters.AppInfoTableAdapter appInfoTableAdapter; // The AnywhereTS application data adapter for the AppInfo table. Only this adapter should be used.
40
41 public static string strDatabaseServer; // If this computer does not contain the database server, this is the name of the database server that contains the ATS database. Used by the Control Panel
42
43 // Directories
44 public static string strDatabasePath; // The directory where the database file is located.
45 public static string strDestDir; // Destination directory for client files in unmanaged mode.
46
47 // Constructor Initializes the global variables
48 static ProSupport()
49 {
50 // Initiate variables from registry
51 strDatabasePath = ATSGlobals.GetATSRegValueString(strRegDatabaseDir);
52 strDestDir = ATSGlobals.GetATSRegValueString(strRegDestDir);
53 strDatabaseServer = ATSGlobals.GetATSRegValueString(strRegDatabaseServer);
54 }
55
56 // Loook up local IP for computer
57 public static void ThisComputerIp (System.Windows.Forms.ComboBox combo, bool bolServerName)
58 {
59 ManagementObjectSearcher query = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = 'TRUE'");
60
61 ManagementObjectCollection queryCollection = query.Get();
62 combo.Items.Clear();
63 if (bolServerName == true) //Add computer name
64 {
65 combo.Items.Add(Dns.GetHostName());
66 }
67 foreach (ManagementObject mo in queryCollection)
68 {
69 string[] addresses = (string[])mo["IPAddress"];
70 foreach (string ipaddress in addresses)
71 {
72 if (ipaddress !="0.0.0.0")
73 combo.Items.Add(ipaddress);
74
75 }
76 }
77 }
78
79 // Compate two DriveInfo arrays and return TRUE if they are equal.
80 public static bool CompareDriveInfoArrays(List<DriveInfo> data1, List<DriveInfo> data2)
81 {
82 // If both are null, they're equal
83 if (data1 == null && data2 == null)
84 {
85 return true;
86 }
87 // If either but not both are null, they're not equal
88 if (data1 == null || data2 == null)
89 {
90 return false;
91 }
92 if (data1.Count != data2.Count)
93 {
94 return false;
95 }
96 for (int i = 0; i < data1.Count; i++)
97 {
98 if (data1[i].Name + data1[i].VolumeLabel != data2[i].Name + data2[i].VolumeLabel)
99 {
100 return false;
101 }
102 }
103 return true;
104 }
105
106 // Get an IP parameter (IP, netmask, gateway) from the local machine
107 // Paramters:
108 // Out: IP address in the format "x.x.x.x"
109 // strNetworkConf = "IPAddress": Get IPAddress
110 // strNetworkConf = "IPSubnet": Get netmask
111 // strNetworkConf = "DefaultIPGateway": Get gateway
112 // strNetworkConf = "Description": Get network card
113 // strNetworkConf = "MACAddress": Get MAC address
114 // strNetworkConf = "DNSServerSearchOrder": Get DNS
115 public static string ThisComputerNetworkConf(string strNetworkConf)
116 {
117 ManagementObjectSearcher query = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = 'TRUE'");
118 ManagementObjectCollection queryCollection = query.Get();
119 foreach (ManagementObject mo in queryCollection)
120 {
121 string[] addresses = (string[])mo[strNetworkConf];
122 return addresses[0];
123 }
124 return ""; // No network adapter found.
125 }
126
127 // Initiate the database
128 public static void InitDatabase()
129 {
130 //// Create and set the connection string
131 //string dataServerName; // The name of the database server in the connection string
132 //if (strDatabaseServer.Length != 0)
133 //{ // We have a database server
134 // dataServerName = strDatabaseServer;
135 //}
136 //else
137 //{ // We do not have an external, data server.
138 // dataServerName = ".";
139 //}
140 //Properties.Settings.Default["atsConnectionString"] = @"Data Source=" + dataServerName + @"\SQLEXPRESS;Database='AnywhereTS';Integrated Security=True;Connect Timeout=30;User Instance=False";
141 //Properties.Settings.Default.Save();
142
143 // Set up table adapters
144 clientTableAdapter = new atsDataSetTableAdapters.ClientTableAdapter();
145 tftpServerTableAdapter = new atsDataSetTableAdapters.TftpServerTableAdapter();
146 terminalServerTableAdapter = new atsDataSetTableAdapters.TerminalServerTableAdapter();
147 appInfoTableAdapter = new atsDataSetTableAdapters.AppInfoTableAdapter();
148 }
149
150 // Adds an ACL entry for RW access on the specified file for Remote desktop users.
151 public static void GrantRWaccessForRemoteDesktopUsers(string fileName)
152 {
153 // Get a FileSecurity object that represents the current security settings.
154 FileSecurity fSecurity = File.GetAccessControl(fileName);
155
156 // Add FileSystemAccessRule:s to the security settings.
157 // Remote desktop users can read and write, but not delete
158 fSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinRemoteDesktopUsersSid, null), FileSystemRights.Read, AccessControlType.Allow));
159 fSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinRemoteDesktopUsersSid, null), FileSystemRights.Write, AccessControlType.Allow));
160
161 // Set the new access settings.
162 File.SetAccessControl(fileName, fSecurity);
163 }
164
165 // Adds an ACL entry for ReadWriteModify access on the specified file for Remote desktop users.
166 public static void GrantRWMaccessForRemoteDesktopUsers(string fileName)
167 {
168 // Get a FileSecurity object that represents the current security settings.
169 FileSecurity fSecurity = File.GetAccessControl(fileName);
170
171 // Add FileSystemAccessRule:s to the security settings.
172 // Remote desktop users can read and write, but not delete
173 fSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinRemoteDesktopUsersSid, null), FileSystemRights.Read, AccessControlType.Allow));
174 fSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinRemoteDesktopUsersSid, null), FileSystemRights.Write, AccessControlType.Allow));
175 fSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinRemoteDesktopUsersSid, null), FileSystemRights.Modify, AccessControlType.Allow));
176
177 // Set the new access settings.
178 File.SetAccessControl(fileName, fSecurity);
179 }
180
181 // (obsolete)
182 // Adds an ACL entry for to deny modify access on the specified file for all users.
183 public static void DenyAccessRightModifyForUsers(string fileName)
184 {
185 // Get a FileSecurity object that represents the current security settings.
186 FileSecurity fSecurity = File.GetAccessControl(fileName);
187
188 // Add FileSystemAccessRule:s to the security settings.
189 // Remote desktop users can read and write, but not delete
190 fSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), FileSystemRights.Write, AccessControlType.Deny));
191 fSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), FileSystemRights.Modify, AccessControlType.Deny));
192
193 // Set the new access settings.
194 File.SetAccessControl(fileName, fSecurity);
195 }
196
197
198 // Writes config files to all of the TFTP directories definied in registry and database,
199 // and set rights.
200 public static void WriteConfigFiles(ATSImageRuntimeConfig config, string fileName, bool setRights)
201 { // config: The config that should be written to disk
202 // fileName: Name of the config file to write
203 // setRights: True = Set access rights on the file, so that all remote desktop users can delete the file.
204 // Write client config file
205
206 if (ATSGlobals.tftpConfig == 0)
207 { // Use ATS TFTP
208 WriteConfigFile(config, ATSGlobals.strTFTPdir + @"\" + fileName, setRights);
209 }
210 else if (ATSGlobals.tftpConfig == 1)
211 { // External TFTP
212 // Write the config file to all TFTP directories
213 atsDataSet.TftpServerDataTable datatableTFTP; // TFTP server directories
214 atsDataSetTableAdapters.TftpServerTableAdapter tftpServerTableAdapter; // The AnywhereTS application data adapter for the TFTP servers table. Only this adapter should be used.
215
216 tftpServerTableAdapter = new AnywhereTS.atsDataSetTableAdapters.TftpServerTableAdapter();
217 datatableTFTP = new atsDataSet.TftpServerDataTable();
218
219 tftpServerTableAdapter.Fill(datatableTFTP);
220 foreach (DataRow row in datatableTFTP.Rows)
221 {
222 WriteConfigFile(config, GetTftpPath(row) + @"\" + fileName, setRights);
223 }
224 }
225 else
226 throw new Exception("Unknown TFTP mode 28158");
227 }
228
229 // Copy image file to all external tftp directories/servers
230 public static void CopyImageFile(string path, string sourceFileName, string destFileName)
231 {
232 atsDataSet.TftpServerDataTable datatableTFTP; // TFTP server directories
233 datatableTFTP = new atsDataSet.TftpServerDataTable();
234 atsDataSetTableAdapters.TftpServerTableAdapter tftpServerTableAdapter; // The AnywhereTS application data adapter for the TFTP servers table. Only this adapter should be used.
235 tftpServerTableAdapter = new AnywhereTS.atsDataSetTableAdapters.TftpServerTableAdapter();
236
237 tftpServerTableAdapter.Fill(datatableTFTP);
238 foreach (DataRow row in datatableTFTP.Rows)
239 {
240 // Copy to the TFTP server
241 try
242 {
243 File.Copy(path + @"\" + sourceFileName, GetTftpPath(row) + @"\" + destFileName, true);
244 }
245 catch (Exception e)
246 {
247 MessageBox.Show("Could not update TFTP server '" + GetTftpPath(row) + "' (22181). Error: " + e.Message);
248 }
249
250 // Try to set rights for image the image file
251 // (not implemented)
252 /*
253 try
254 {
255 DenyAccessRightModifyForUsers(row["Path"].ToString() + @"\" + file);
256 }
257 catch (Exception e)
258 {
259 MessageBox.Show("Could not set rights for image file on TFTP server '" + row["Path"].ToString() + "' (22183). Error: " + e.Message);
260 } */
261 }
262 }
263
264 // Create subdirectory in all external tftp directories/servers
265 public static void CreateDirectoryOnTFTP_servers(string directoryName)
266 {
267 atsDataSet.TftpServerDataTable datatableTFTP; // TFTP server directories
268 datatableTFTP = new atsDataSet.TftpServerDataTable();
269 atsDataSetTableAdapters.TftpServerTableAdapter tftpServerTableAdapter; // The AnywhereTS application data adapter for the TFTP servers table. Only this adapter should be used.
270 tftpServerTableAdapter = new AnywhereTS.atsDataSetTableAdapters.TftpServerTableAdapter();
271
272 tftpServerTableAdapter.Fill(datatableTFTP);
273 foreach (DataRow row in datatableTFTP.Rows)
274 {
275 // Create the Directory on the TFTP server
276 try
277 {
278 Directory.CreateDirectory(GetTftpPath(row) + @"\" + directoryName);
279 }
280 catch (Exception e)
281 {
282 MessageBox.Show("Could not update TFTP server '" + GetTftpPath(row) + "' (22381). Error: " + e.Message);
283 }
284 }
285 }
286
287 public static void WriteConfigFile(ATSImageRuntimeConfig config, string path, bool setRights)
288 {
289 config.WriteConfigFile(path);
290
291 if (setRights)
292 {
293 // Set access rights for the config file.
294 try
295 {
296 // Add an access control entry to the config file.
297 ProSupport.GrantRWMaccessForRemoteDesktopUsers(path);
298 }
299 catch (Exception ex)
300 {
301 MessageBox.Show("Cannot set access rights for client configuration. Application will abort. Error: " + ex.Message);
302 Application.Exit();
303 return;
304 }
305 }
306 }
307
308
309 // Writes host files to all of the TFTP directories definied in registry and database.
310 public static void WriteHostsFiles()
311 {
312 if (ATSGlobals.tftpConfig == 0)
313 { // Use ATS TFTP
314 WriteHostsFile(ATSGlobals.strTFTPdir + @"\" + strHostsFilename);
315 }
316 else if (ATSGlobals.tftpConfig == 1)
317 { // External TFTP
318 // Write the config file to all TFTP directories
319 atsDataSet.TftpServerDataTable datatableTFTP; // TFTP server directories
320 datatableTFTP = new atsDataSet.TftpServerDataTable();
321 tftpServerTableAdapter.Fill(datatableTFTP);
322 foreach (DataRow row in datatableTFTP.Rows)
323 {
324 WriteHostsFile(GetTftpPath(row) + @"\" + strHostsFilename);
325 }
326 }
327 else
328 throw new Exception("Unknown TFTP mode 48158");
329 }
330
331
332 // Create a (new) encrypted hosts file from data in the database.
333 private static void WriteHostsFile(string path)
334 {
335 atsDataSet datasetClient = new atsDataSet();
336 ProSupport.clientTableAdapter.FillClients(datasetClient.Client);
337
338 // System.IO.StreamWriter writer = null;
339 CryptStream writer = null;
340
341 // Delete old hosts file
342 if (System.IO.File.Exists(path))
343 {
344 System.IO.File.Delete(path);
345 }
346
347 // Write a new hosts file.
348 try
349 {
350 //writer = new System.IO.StreamWriter(path);
351 writer = new CryptStream(path);
352 writer.NewLine = "\n"; // Unix style line terminators
353 writer.WriteLine("# This is a hosts file generated by AnywhereTS. Do not change.");
354 foreach (DataRow row in datasetClient.Client.Rows)
355 {
356 writer.WriteLine(row["ClientName"].ToString() + " " + row["MacAddress"].ToString());
357 }
358 writer.WriteLine("# Detta e slutet."); // Termination string to avoid decryptation bug.
359 }
360 catch (Exception e)
361 {
362 //improve autoretry
363 MessageBox.Show("Error: Could not write configuration data to disk. Possibly the data is being accessed by another component right now or you do not have the sufficient rights. Please retry this operation later (52044). Error details: " + e.Message);
364 }
365
366 finally
367 {
368 if (writer != null)
369 writer.Close();
370 }
371
372 // DenyAccessRightModifyForUsers(path); // Prevent users from deleting or modifying the hosts file.
373 }
374
375
376 // Check if user is administrator
377 // Returns true if user is administrator
378 public static bool IsAnAdministrator()
379 {
380 WindowsIdentity identity =
381 WindowsIdentity.GetCurrent();
382 WindowsPrincipal principal =
383 new WindowsPrincipal(identity);
384 return principal.IsInRole
385 (WindowsBuiltInRole.Administrator);
386 }
387
388 public static string GetMacAddressFromNameAndDatabase(string strName)
389 {
390 string macAddress;
391 // Try to extract MAC address from client name.
392 macAddress = ATSGlobals.GetMacFromATSname(strName);
393 if (macAddress.Length == 0)
394 { // MAC not in name, try to lookup client name in database
395 atsDataSet datasetClientName = new atsDataSet();
396 // Update dataset with the client row matching the name
397 try
398 {
399 ProSupport.clientTableAdapter.FillOnName(datasetClientName.Client, strName);
400 }
401 catch
402 { // Error when accessing database
403 return "";
404 }
405 if (datasetClientName.Client.Rows.Count > 0)
406 { // Client row found in database
407 macAddress = datasetClientName.Client.Rows[0]["MacAddress"].ToString();
408 }
409 else
410 { // Name not found
411 macAddress = "";
412 }
413 }
414 return macAddress;
415 }
416
417 // Re-writes all config files, so that they will be containing new parameters.
418 // Also creates config files if they have been deleted, i.e by an expired beta.
419 public static void RecreateConfigFiles()
420 {
421 // Re-create all config files
422 if (ATSGlobals.tftpConfig == 0)
423 { // Use ATS TFTP
424 WriteConfigFiles(ATSGlobals.strTFTPdir);
425 }
426 else if (ATSGlobals.tftpConfig == 1)
427 { // External TFTP
428 // Write the config file to all TFTP directories
429 atsDataSet.TftpServerDataTable datatableTFTP; // TFTP server directories
430 datatableTFTP = new atsDataSet.TftpServerDataTable();
431 tftpServerTableAdapter.Fill(datatableTFTP);
432 foreach (DataRow row in datatableTFTP.Rows)
433 {
434 // Write to TFTP path
435 WriteConfigFiles(GetTftpPath(row));
436 }
437 }
438 else
439 throw new Exception("Unknown TFTP mode 88158");
440
441 WriteHostsFiles();
442 ATSImageRuntimeConfig currentConfig = new ATSImageRuntimeConfig();
443 currentConfig.ReadDefaultFromDatabase();
444 ProSupport.WriteConfigFiles(currentConfig, ProSupport.strNetworkConfigFilename, false);
445 }
446
447
448 static void WriteConfigFiles(string strDirectory)
449 {
450 ATSImageRuntimeConfig currentConfig = new ATSImageRuntimeConfig();
451 atsDataSet datasetClient = new atsDataSet();
452 ProSupport.clientTableAdapter.FillClients(datasetClient.Client);
453 string strFilePath;
454 foreach (DataRow row in datasetClient.Client.Rows)
455 {
456 // Write the config file corresponding to the client
457 currentConfig.ReadFromDatabase(row);
458 strFilePath = strDirectory + @"\" + row["MacAddress"];
459 currentConfig.WriteConfigFile(strFilePath);
460 }
461 }
462
463 // Return a local or UNC path for TFTP server, depending on what it best.
464 public static string GetTftpPath(DataRow tftpRow)
465 {
466 // Extract computer name from UNC Path
467 string uncPath = tftpRow["Path"].ToString();
468 string uncComputer = uncPath.Substring(2, uncPath.IndexOf(@"\", 2) - 2);
469 if (uncComputer.ToUpper() == Environment.MachineName)
470 { // The UNC path resides on this computer, use a local path if it is available
471 if (tftpRow["LocalPath"].ToString().Length > 0)
472 { // We have a local path
473 return tftpRow["LocalPath"].ToString();
474 }
475 else
476 { // No local path, we have to go with the UNC path referring to the local machine.
477 return tftpRow["Path"].ToString();
478 }
479 }
480 else
481 { // The UNC path does not reside on this computer, use it as it is.
482 return tftpRow["Path"].ToString();
483 }
484 }
485
486
487 // Sub routines used by wizard for screen resolution
488 //-----------------------------------------------------
489
490 public static void UpdateScreenResolutionControls(int x, int y, TextBox txtScreenResX, TextBox txtScreenResY, TrackBar tbrScreenResolution)
491 {
492 txtScreenResX.Text = x.ToString();
493 txtScreenResY.Text = y.ToString();
494
495 for (int i = 0; i < ATSGlobals.ScreenResolutions.GetLength(0); i++)
496 {
497 if (x == ATSGlobals.ScreenResolutions[i, 0] && y == ATSGlobals.ScreenResolutions[i, 1])
498 {
499 tbrScreenResolution.Value = i + 1;
500 return;
501 }
502
503 }
504 // Values could not be expressed using the track bar. Set it at default.
505 tbrScreenResolution.Value = 4;
506 }
507
508 public static void GetScreenResolutionFromTrackbar(TrackBar tbr, out int x, out int y)
509 {
510 x = ATSGlobals.ScreenResolutions[tbr.Value - 1, 0];
511 y = ATSGlobals.ScreenResolutions[tbr.Value - 1, 1];
512 }
513
514 public static void UpdateResolutionTrackbar(TextBox txtScreenResX, TextBox txtScreenResY, TrackBar tbrScreenResolution)
515 { // Try to convert x, y values to trackbar.
516 int x, y;
517 try
518 {
519 x = Int32.Parse(txtScreenResX.Text.Trim());
520 }
521 catch (Exception)
522 {
523 x = 0;
524 }
525
526 try
527 {
528 y = Int32.Parse(txtScreenResY.Text.Trim());
529 }
530 catch (Exception)
531 {
532 y = 0;
533 }
534
535 UpdateScreenResolutionControls(x, y, txtScreenResX, txtScreenResY, tbrScreenResolution);
536 }
537
538
539
540 public static void copyDirectory(string Src,string Dst)
541 {
542 String[] Files;
543
544 if(Dst[Dst.Length-1]!=Path.DirectorySeparatorChar)
545 Dst+=Path.DirectorySeparatorChar;
546 if(!Directory.Exists(Dst)) Directory.CreateDirectory(Dst);
547 Files=Directory.GetFileSystemEntries(Src);
548 foreach(string Element in Files){
549 // Sub directories
550
551 if(Directory.Exists(Element))
552 copyDirectory(Element,Dst+Path.GetFileName(Element));
553 // Files in directory
554
555 else
556 File.Copy(Element,Dst+Path.GetFileName(Element), true);
557 }
558 }
559
560
561
562
563 } // end class Prosupport
564
565
566 public class CryptStream : StreamWriter
567 {
568 BinaryWriter outStream;
569
570 const byte offset1 = 36;
571 const byte offset2 = 0xab;
572 const byte key = 0x36;
573 byte value;
574
575 public CryptStream(string s)
576 : base(s)
577 {
578 // Base constructor has created a stream. Steal it.
579 outStream = new BinaryWriter(base.BaseStream);
580 WriteHeader();
581 }
582
583
584 public CryptStream(Stream s)
585 : base(s)
586 {
587 outStream = new BinaryWriter(s);
588 WriteHeader();
589 }
590
591
592 private void WriteHeader()
593 {
594 outStream.Write((byte)0x41);
595 outStream.Write((byte)0x54);
596 outStream.Write((byte)0x53);
597 outStream.Write((byte)0x78);
598 value = key;
599 }
600
601
602 private byte Crypt(byte ch1)
603 {
604 byte ch2 = (byte)((ch1 + offset1) & 0xFF);
605 byte ch3 = (byte)((ch2 ^ value) & 0xFF);
606 value = (byte)((value + offset2) & 0xFF);
607 return ch3;
608 }
609
610 public override void Write(string s)
611 {
612 for (int i = 0; i < s.Length; i++)
613 outStream.Write(Crypt((byte)s[i]));
614 }
615
616
617 public override void WriteLine(string s)
618 {
619 Write(s);
620 Write("\n");
621 }
622 }
623
624 } //end namespace

  ViewVC Help
Powered by ViewVC 1.1.22