1: using Dart.PowerTCP.Telnet;
2: using System;
3: using System.Collections.Generic;
4: using System.Diagnostics;
5:
6: namespace Ia.Ngn.Cl.Model.Client.Huawei
7: {
8: ////////////////////////////////////////////////////////////////////////////
9:
10: /// <summary publish="true">
11: /// Optical Fiber Network's Operations Support System Management Intranet (OFN OSS) client support class for Huawei's Optical Fiber Network (OFN) EMS client model.
12: /// </summary>
13: ///
14: /// <remarks>
15: /// Copyright © 2017-2022 Jasem Y. Al-Shamlan (info@ia.com.kw), Integrated Applications - Kuwait. All Rights Reserved.
16: ///
17: /// This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
18: /// the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
19: ///
20: /// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
21: /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
22: ///
23: /// You should have received a copy of the GNU General Public License along with this library. If not, see http://www.gnu.org/licenses.
24: ///
25: /// Copyright notice: This notice may not be removed or altered from any source distribution.
26: /// </remarks>
27: public class Ems
28: {
29: private bool isLoggedIn;
30:
31: // interactive Telnet does not require a very large buffer, so 1024 is fine
32: private readonly byte[] buffer = new byte[1024];
33: private string receiveString;
34: internal Telnet telnet;
35:
36: /// <summary/>
37: public static int WaitAfterSendInMillisecond { get { return 4000; } }
38:
39: public static int WaitAfterSendForCfgCommandInMillisecond { get { return 10000; } }
40:
41: public string LastSentCommand { get; private set; }
42:
43: public Queue<string> ReceiveQueue { get; set; }
44:
45: public Queue<string> SendQueue { get; set; }
46:
47: public Queue<string> SystemIsBusyResendQueue { get; set; }
48:
49: public Queue<string> OntLoadingCommandIsBeingExecutedNowResendQueue { get; set; }
50:
51: public Dictionary<string, DateTime> OntSipInfoCommandAgainAfterNSecondsToDateTimeDictionary { get; set; }
52:
53: public Queue<string> OntSipInfoCommandAgainAfterNSecondsResendQueue { get; set; }
54:
55: ////////////////////////////////////////////////////////////////////////////
56:
57: /// <summary>
58: ///
59: /// </summary>
60: public enum ResultCode : long
61: {
62: // I'm basically using the almost exact document phrasing of error codes
63: Unknown = -1,
64: Succeeded = 0,
65: DeviceDoesNotExist1 = 2686058531,
66: DeviceDoesNotExist2 = 15658136501,
67: ResourceDoesNotExist = 2686058552,
68: OntIsNotOnline = 2689012370,
69: CommunicatingWithDmFailed = 2686058603,
70: OntIsOffline = 2689014724,
71: OntLoadingCommandIsBeingExecutedNow = 2689014933,
72: SystemIsBusy1 = 2686058516,
73: SystemIsBusy2 = 2689017157,
74: AttempetingTimeout = 2686058596,
75: CommandSyntaxError = 2686058497,
76: UnknownCommand = 2686058499,
77: TaskTimeout = 2686058508,
78: ValueOfParameterIsWrong = 2686058500,
79: DbaProfileDoesNotExist1 = 102690820,
80: DbaProfileDoesNotExist2 = 2689014791,
81: NodeParameterSetFailed = 1615069195,
82: VersionDoesNotMatchOrCommunicationWithDeviceFailed = 1615462437,
83: FailedToCommunicateWithDevice1 = 1610614842,
84: FailedToCommunicateWithDevice2 = 1616445483,
85: FailedToCommunicateWithDevice3 = 1616445484,
86: FailedToCommunicateWithDevice4 = 1616445485,
87: LoginAddressIsNotInUserAcl = 76546022,
88: LoginAddressIsNotInSystemAcl = 76546023,
89: DeviceOfflineError = 1610612765,
90: OperationIsNotSupported = 2689008176,
91: ParametersConflictWithVasProfile = 1615069206,
92: ProfileAlreadyExists = 2689023090,
93: TrafficProfileDoesNotExist = 2689020327,
94: MgParameterIsConflicting = 2688880284,
95: NoOnuTypeIsSetInGeneralProfile = 1618280538,
96: OntIsUsedByOthers = 1618214927,
97: UserDoesNotLogIn = 2686058521,
98: PortDoesNotExist = 2689015666,
99: TelephoneNumberAlreadyExists = 2689015764,
100: ThePasswordHasExpiredOrNeedsToBeChangedOnNextLogin = 1618280766,
101: TheUserAccountIsLocked = 76546024,
102: TheOntDoesNotSuppportConfigeringValueAddedServiceWithoutBindingGeneralVasProfile = 1615069214,
103: NoMatchingPortPleaseCheckTheDataSetting = 2686059269,
104: AnInstanceUnknownToTheAgentIsDesignated = 2689007637,
105: ThePortIsNotConfiguredMgUserData = 2689015732,
106: PortHasBeenConfiguredWithUserData = 2689015744,
107: TheCpeIsNotExistent = 161503642,
108: TheVersionIsNotConfigurable = 1615069190,
109: }
110:
111: ////////////////////////////////////////////////////////////////////////////
112:
113: /// <summary>
114: ///
115: /// </summary>
116: public static string ResultCodeString(long _resultCode)
117: {
118: // see: ColoredResultCodeString()
119: string resultCodeString;
120: Ia.Ngn.Cl.Model.Client.Huawei.Ems.ResultCode resultCode;
121:
122: resultCode = (Ia.Ngn.Cl.Model.Client.Huawei.Ems.ResultCode)_resultCode;
123:
124: resultCodeString = resultCode.ToString();
125: resultCodeString = Ia.Cl.Model.Default.CamelToProperCase(resultCodeString);
126: resultCodeString = Ia.Cl.Model.Default.ToTitleCase(resultCodeString);
127: resultCodeString = resultCodeString.Replace("Ont", "ONT");
128:
129: return resultCodeString;
130: }
131:
132: ////////////////////////////////////////////////////////////////////////////
133:
134: /// <summary>
135: ///
136: /// </summary>
137: public static string ColoredResultCodeString(long _resultCode)
138: {
139: // see: ResultCodeString()
140: string resultCodeString, coloredResultCodeString;
141: Ia.Ngn.Cl.Model.Client.Huawei.Ems.ResultCode resultCode;
142:
143: resultCode = (Ia.Ngn.Cl.Model.Client.Huawei.Ems.ResultCode)_resultCode;
144:
145: resultCodeString = resultCode.ToString();
146: resultCodeString = Ia.Cl.Model.Default.CamelToProperCase(resultCodeString);
147: resultCodeString = Ia.Cl.Model.Default.ToTitleCase(resultCodeString);
148: resultCodeString = resultCodeString.Replace("Ont", "ONT");
149:
150: switch (resultCode)
151: {
152: case Ia.Ngn.Cl.Model.Client.Huawei.Ems.ResultCode.Succeeded: coloredResultCodeString = "<span style=\"color:Green\">" + resultCodeString + "</span>"; break;
153: case Ia.Ngn.Cl.Model.Client.Huawei.Ems.ResultCode.SystemIsBusy2: coloredResultCodeString = "<span style=\"color:MediumPurple\">" + resultCodeString + "</span>"; break;
154: case Ia.Ngn.Cl.Model.Client.Huawei.Ems.ResultCode.OntIsOffline: coloredResultCodeString = "<span style=\"color:OrangeRed\">" + resultCodeString + "</span>"; break;
155: case Ia.Ngn.Cl.Model.Client.Huawei.Ems.ResultCode.DeviceOfflineError: coloredResultCodeString = "<span style=\"color:Red\">" + resultCodeString + "</span>"; break;
156: default: coloredResultCodeString = "<span style=\"color:Blue\">" + resultCodeString + "</span>"; break;
157: }
158:
159: return coloredResultCodeString;
160: }
161:
162: ////////////////////////////////////////////////////////////////////////////
163:
164: /// <summary>
165: ///
166: /// </summary>
167: public Ems()
168: {
169: this.telnet = new Dart.PowerTCP.Telnet.Telnet(); // this.components);
170:
171: this.telnet.ClientOptions.AddRange(new Dart.PowerTCP.Telnet.Option[] {
172: new Dart.PowerTCP.Telnet.Option(Dart.PowerTCP.Telnet.OptionCode.SuppressGoAheads, null, Dart.PowerTCP.Telnet.OptionState.RequestOn),
173: new Dart.PowerTCP.Telnet.Option(Dart.PowerTCP.Telnet.OptionCode.WindowSize, new byte[] {((byte)(0)),((byte)(80)),((byte)(0)),((byte)(24))}, Dart.PowerTCP.Telnet.OptionState.RequestOn),
174: new Dart.PowerTCP.Telnet.Option(Dart.PowerTCP.Telnet.OptionCode.TerminalType, new byte[] {((byte)(0)),((byte)(120)),((byte)(116)),((byte)(101)),((byte)(114)),((byte)(109))}, Dart.PowerTCP.Telnet.OptionState.RequestOn)});
175:
176: this.telnet.ServerOptions.AddRange(new Dart.PowerTCP.Telnet.Option[] {
177: new Dart.PowerTCP.Telnet.Option(Dart.PowerTCP.Telnet.OptionCode.SuppressGoAheads, null, Dart.PowerTCP.Telnet.OptionState.RequestOn),
178: new Dart.PowerTCP.Telnet.Option(Dart.PowerTCP.Telnet.OptionCode.Echo, null, Dart.PowerTCP.Telnet.OptionState.RequestOn)});
179:
180: //this.telnet.SynchronizingObject = this;
181: this.telnet.TerminalType = "xterm";
182: //this.telnet.WindowSize = new System.Drawing.Size(80, 24);
183: this.telnet.EndReceive += new Dart.PowerTCP.Telnet.SegmentEventHandler(this.Telnet_EndReceive);
184: this.telnet.ConnectedChangedEx += new Dart.PowerTCP.Telnet.EventHandlerEx(this.Telnet_ConnectedChangedEx);
185:
186: receiveString = string.Empty;
187:
188: ReceiveQueue = new Queue<string>();
189: SendQueue = new Queue<string>();
190: SystemIsBusyResendQueue = new Queue<string>();
191: OntLoadingCommandIsBeingExecutedNowResendQueue = new Queue<string>();
192:
193: OntSipInfoCommandAgainAfterNSecondsToDateTimeDictionary = new Dictionary<string, DateTime>();
194: OntSipInfoCommandAgainAfterNSecondsResendQueue = new Queue<string>();
195:
196: isLoggedIn = false;
197: }
198:
199: ////////////////////////////////////////////////////////////////////////////
200:
201: /// <summary>
202: ///
203: /// </summary>
204: ~Ems()
205: {
206: Dispose();
207: }
208:
209: ////////////////////////////////////////////////////////////////////////////
210:
211: /// <summary>
212: ///
213: /// </summary>
214: public void Connect(out Ia.Cl.Model.Result result)
215: {
216: result = new Ia.Cl.Model.Result();
217:
218: try
219: {
220: telnet.ClientOptions.Add(new Dart.PowerTCP.Telnet.Option(Dart.PowerTCP.Telnet.OptionCode.SuppressGoAheads, null, Dart.PowerTCP.Telnet.OptionState.RequestOn));
221: telnet.ClientOptions.Add(new Dart.PowerTCP.Telnet.Option(Dart.PowerTCP.Telnet.OptionCode.TerminalType, new System.Byte[] { ((System.Byte)(0)), ((System.Byte)(116)), ((System.Byte)(116)), ((System.Byte)(121)) }, Dart.PowerTCP.Telnet.OptionState.RequestOn));
222: telnet.ServerOptions.Add(new Dart.PowerTCP.Telnet.Option(Dart.PowerTCP.Telnet.OptionCode.SuppressGoAheads, null, Dart.PowerTCP.Telnet.OptionState.RequestOn));
223: telnet.ServerOptions.Add(new Dart.PowerTCP.Telnet.Option(Dart.PowerTCP.Telnet.OptionCode.Echo, null, Dart.PowerTCP.Telnet.OptionState.RequestOn));
224: telnet.ServerOptions.Add(new Dart.PowerTCP.Telnet.Option(Dart.PowerTCP.Telnet.OptionCode.OutputPageSize, null, Dart.PowerTCP.Telnet.OptionState.RequestOn));
225:
226: telnet.Connect(Ia.Ngn.Cl.Model.Business.Huawei.Ems.Host, Ia.Ngn.Cl.Model.Business.Huawei.Ems.Port.ToString());
227:
228: // receive using asynchronous technique
229: telnet.ReceiveTimeout = 0;
230: telnet.BeginReceive(buffer);
231:
232: result.AddSuccess("Connected. ");
233: }
234: catch (Exception ex)
235: {
236: result.AddError("Exception: " + ex.Message);
237:
238: telnet.Close();
239: }
240: }
241:
242: ////////////////////////////////////////////////////////////////////////////
243:
244: /// <summary>
245: ///
246: /// </summary>
247: public void Disconnect(out Ia.Cl.Model.Result result)
248: {
249: result = new Ia.Cl.Model.Result();
250:
251: try
252: {
253: telnet.Close();
254:
255: result.AddSuccess("Disconnected. ");
256: }
257: catch (Exception ex)
258: {
259: result.AddError(ex.Message);
260: }
261: }
262:
263: ////////////////////////////////////////////////////////////////////////////
264:
265: /// <summary>
266: ///
267: /// </summary>
268: public bool IsConnected
269: {
270: get
271: {
272: return telnet.Connected;
273: }
274: }
275:
276: ////////////////////////////////////////////////////////////////////////////
277:
278: /// <summary>
279: ///
280: /// </summary>
281: public bool IsLoggedIn { get { return isLoggedIn; } set { isLoggedIn = value; } }
282:
283: ////////////////////////////////////////////////////////////////////////////
284:
285: /// <summary>
286: ///
287: /// </summary>
288: public void Dispose()
289: {
290: telnet.Dispose();
291: }
292:
293: ////////////////////////////////////////////////////////////////////////////
294:
295: /// <summary>
296: ///
297: /// </summary>
298: public void Login()
299: {
300: // sendQueue.Enqueue(Ia.Ngn.Cl.Model.Business.Huawei.Ems.Semicolon); did not make any different
301:
302: // below: I need this because NCE somehow needs to be triggered before I send login information
303: SendQueue.Enqueue(Ia.Ngn.Cl.Model.Business.Huawei.Ems.EmsKeepAliveCommand);
304: SendQueue.Enqueue(Ia.Ngn.Cl.Model.Business.Huawei.Ems.EmsKeepAliveCommand);
305:
306: SendQueue.Enqueue(Ia.Ngn.Cl.Model.Business.Huawei.Ems.LoginUser);
307: }
308:
309: ////////////////////////////////////////////////////////////////////////////
310:
311: /// <summary>
312: ///
313: /// </summary>
314: public void Logout()
315: {
316: SendQueue.Enqueue(Ia.Ngn.Cl.Model.Business.Huawei.Ems.LogoutUser);
317: }
318:
319: ////////////////////////////////////////////////////////////////////////////
320:
321: /// <summary>
322: ///
323: /// </summary>
324: public void Send(string text, bool skipSleep, out Ia.Cl.Model.Result result)
325: {
326: result = new Ia.Cl.Model.Result();
327:
328: try
329: {
330: if (telnet.Connected)
331: {
332: if (text != null)
333: {
334: LastSentCommand = text;
335:
336: //this.textBox.AppendText("\r\n/* Sending: " + text + " */\r\n");
337:
338: telnet.Send(text);
339:
340: result.AddSuccess("Sent: [" + text + "]");
341: }
342: else
343: {
344: result.AddError("No text to send.");
345: }
346: }
347: else
348: {
349: result.AddError("No established telnet connection.");
350: //if(processRunning) waitToConnectionCounter = waitToConnectionCounterSeconds;
351: }
352: }
353: catch (Exception ex)
354: {
355: //if(processRunning) waitToConnectionCounter = waitToConnectionCounterSeconds;
356:
357: result.AddError(ex.Message);
358: }
359:
360: if (!skipSleep)
361: {
362: // this is meant to give the Telnet_EndReceive() time to receive and process data from session
363: // we will wait according to the type of commands send
364:
365: if (Ia.Ngn.Cl.Model.Business.Huawei.Ems.IsACfgCommand(LastSentCommand))
366: {
367: System.Threading.Thread.Sleep(Ia.Ngn.Cl.Model.Client.Huawei.Ems.WaitAfterSendForCfgCommandInMillisecond);
368: }
369: else
370: {
371: System.Threading.Thread.Sleep(Ia.Ngn.Cl.Model.Client.Huawei.Ems.WaitAfterSendInMillisecond);
372: }
373: }
374: }
375:
376: ////////////////////////////////////////////////////////////////////////////
377:
378: /// <summary>
379: ///
380: /// </summary>
381: private void Telnet_EndReceive(object sender, Dart.PowerTCP.Telnet.SegmentEventArgs e)
382: {
383: string message, entry;
384: string[] receiveStringSplit;
385:
386: Debug.WriteLine(" ");
387: Debug.WriteLine("============================================");
388:
389: if (e.Exception == null)
390: {
391: receiveString += e.Segment.ToString();
392:
393: Debug.WriteLine("Telnet_EndReceive(): e.Segment: [" + e.Segment.ToString() + "], receiveString: [" + receiveString + "]");
394:
395: if (!string.IsNullOrEmpty(receiveString))
396: {
397: receiveStringSplit = receiveString.Split(new string[] { "\r\n;" }, StringSplitOptions.None);
398:
399: if (receiveStringSplit.Length > 0)
400: {
401: for (int i = 0; i < receiveStringSplit.Length; i++)
402: {
403: entry = receiveStringSplit[i];
404:
405: if (!string.IsNullOrEmpty(entry) && !string.IsNullOrWhiteSpace(entry))
406: {
407: // will not enqueue an empty entry
408:
409: if (i == receiveStringSplit.Length - 1)
410: {
411: // if there is a non empty last entry that means its incomplete and we will assign it to receiveString
412:
413: receiveString = entry;
414: }
415: else
416: {
417: message = entry + "\r\n;"; // important
418:
419: if (!ReceiveQueue.Contains(message))
420: {
421: // will not enqueue duplicate
422:
423: ReceiveQueue.Enqueue(message);
424:
425: Debug.WriteLine("Telnet_EndReceive(): ReceiveQueue.Enqueue(message): [" + message + "]");
426: }
427:
428: receiveString = string.Empty;
429: }
430: }
431: }
432: }
433:
434: Debug.WriteLine("Telnet_EndReceive(): receiveString: [" + receiveString + "]");
435: }
436: else
437: {
438:
439: }
440:
441: if (telnet.Connected) telnet.BeginReceive(buffer);
442: }
443: else
444: {
445: Debug.WriteLine("Telnet_EndReceive(): Exception: " + e.Exception.Message);
446:
447: // I will not throw or handle the exception from the event handler
448: // https://stackoverflow.com/questions/3114543/should-event-handlers-in-c-sharp-ever-raise-exceptions
449: //throw new Exception("Telnet_EndReceive(): " + e.Exception.Message);
450: }
451:
452: Debug.WriteLine("============================================");
453: Debug.WriteLine(" ");
454: }
455:
456: ////////////////////////////////////////////////////////////////////////////
457:
458: /// <summary>
459: ///
460: /// </summary>
461: private void Telnet_ConnectedChangedEx(object sender, System.EventArgs e)
462: {
463: // always raised when Connection is established or closed (Connected property changes)
464:
465: //UpdateToolStripStatusLabel();
466: }
467:
468: ////////////////////////////////////////////////////////////////////////////
469:
470: /// <summary>
471: ///
472: /// </summary>
473: public Ia.Cl.Model.Result Update(string rowData, ref Ia.Ngn.Cl.Model.Client.Huawei.Ems ems, out string systemIsBusyResponseCommand, out string ontLoadingCommandIsBeingExecutedNowResponseCommand)
474: {
475: return Ia.Ngn.Cl.Model.Business.Huawei.Ems.UpdateDatabaseWithEmsCommandOutput(rowData, ref ems, out systemIsBusyResponseCommand, out ontLoadingCommandIsBeingExecutedNowResponseCommand);
476: }
477:
478: ////////////////////////////////////////////////////////////////////////////
479: ////////////////////////////////////////////////////////////////////////////
480: }
481:
482: ////////////////////////////////////////////////////////////////////////////
483: ////////////////////////////////////////////////////////////////////////////
484: }