├── .gitignore
├── DEBUG.md
├── HOWTO.md
├── HOWTOCRYPTO.md
├── README.md
├── img
├── add.png
├── crypto0.jpg
├── crypto1.jpg
├── crypto2.jpg
├── crypto3.jpg
├── crypto4.jpg
├── crypto5.jpg
├── crypto6.jpg
├── crypto7.jpg
├── crypto8.jpg
├── crypto9.jpg
├── delete.png
├── down.png
├── duplicate.png
├── filtering.png
├── image.png
├── man0.png
├── man1.png
├── man10.png
├── man11.png
├── man2.png
├── man3.png
├── man4.png
├── man5.png
├── man6.png
├── man7.png
├── man8.png
├── man9.png
├── new.png
├── open.png
├── save.png
├── up.png
└── wallet.png
└── src
├── AboutForm.Designer.cs
├── AboutForm.cs
├── AboutForm.resx
├── AnytoneEncEncryptionMethodForm.Designer.cs
├── AnytoneEncEncryptionMethodForm.cs
├── AnytoneEncEncryptionMethodForm.resx
├── AnytoneEncEncryptionRow.cs
├── BaseEncryptionRow.cs
├── CFT.csproj
├── CFT.sln
├── CftFile.cs
├── DebugLogsFilteringForm.Designer.cs
├── DebugLogsFilteringForm.cs
├── DebugLogsFilteringForm.resx
├── DisplayAdditionalInfo.cs
├── DisplayAdditionalInfoForm.Designer.cs
├── DisplayAdditionalInfoForm.cs
├── DisplayAdditionalInfoForm.resx
├── DisplayAdditionalInfoValuesEnum.cs
├── DisplayNameAttribute.cs
├── DisplayTagObject.cs
├── DmrActivateOptions.cs
├── DmrActivateOptionsControl.Designer.cs
├── DmrActivateOptionsControl.cs
├── DmrActivateOptionsControl.resx
├── DmrAesEncryptionMethodForm.Designer.cs
├── DmrAesEncryptionMethodForm.cs
├── DmrAesEncryptionMethodForm.resx
├── DmrAesEncryptionRow.cs
├── DmrAesKeyLengthEnum.cs
├── DmrColorCodeEnum.cs
├── DmrEncryptionRow.cs
├── DmrEncyptionValueEnum.cs
├── DmrMfidEnum.cs
├── DmrSelectedActivateOptionsEnum.cs
├── DmrTimeSlotEnum.cs
├── DmrTrunkSystemEnum.cs
├── DsdImport.cs
├── EncryptionMethodEnum.cs
├── EncryptionMethodForm.resx
├── HyteraBPEncryptionMethodForm.Designer.cs
├── HyteraBPEncryptionMethodForm.cs
├── HyteraBPEncryptionMethodForm.resx
├── HyteraBPEncryptionRow.cs
├── HyteraEPEncryptionMethodForm.Designer.cs
├── HyteraEPEncryptionMethodForm.cs
├── HyteraEPEncryptionMethodForm.resx
├── HyteraEPEncryptionRow.cs
├── HyteraKeyLengthEnum.cs
├── IActivateOptions.cs
├── IDmrEncryptionMethod.cs
├── IEncryptionRow.cs
├── ImportForm.Designer.cs
├── ImportForm.cs
├── ImportForm.resx
├── ImportItem.cs
├── KeyMapFunctionEnum.cs
├── KeyMapping.cs
├── KeyMappingForm.Designer.cs
├── KeyMappingForm.cs
├── KeyMappingForm.resx
├── KirisunBPEncryptionMethodForm.Designer.cs
├── KirisunBPEncryptionMethodForm.cs
├── KirisunBPEncryptionMethodForm.resx
├── KirisunBPEncryptionRow.cs
├── KirisunKeyLengthEnum.cs
├── Licensing.cs
├── LicensingForm.Designer.cs
├── LicensingForm.cs
├── LicensingForm.resx
├── ListViewExtensions.cs
├── MacAddressForm.Designer.cs
├── MacAddressForm.cs
├── MacAddressForm.resx
├── MainForm.Designer.cs
├── MainForm.cs
├── MainForm.resx
├── MotorolaBPEncryptionMethod.cs
├── MotorolaBPEncryptionMethodForm.Designer.cs
├── MotorolaBPEncryptionMethodForm.cs
├── MotorolaBPEncryptionMethodForm.resx
├── MotorolaBPEncryptionRow.cs
├── MotorolaEPEncryptionMethodForm.Designer.cs
├── MotorolaEPEncryptionMethodForm.cs
├── MotorolaEPEncryptionMethodForm.resx
├── MotorolaEPEncryptionRow.cs
├── NxdnActivateOptions.cs
├── NxdnCypherTypeEnum.cs
├── NxdnScramblerEncryptionMethodForm.Designer.cs
├── NxdnScramblerEncryptionMethodForm.cs
├── NxdnScramblerEncryptionMethodForm.resx
├── NxdnScramblerEncryptionRow.cs
├── NxdnSelectOptionsEnum.cs
├── NxdnSelectedActivateOptionsEnum.cs
├── P25ADPEncryptionMethodForm.Designer.cs
├── P25ADPEncryptionMethodForm.cs
├── P25ADPEncryptionMethodForm.resx
├── P25ADPEncryptionRow.cs
├── P25AESEncryptionMethodForm.Designer.cs
├── P25AESEncryptionMethodForm.cs
├── P25AESEncryptionMethodForm.resx
├── P25AESEncryptionRow.cs
├── P25ActivateOptions.cs
├── P25ActivateOptionsControl.Designer.cs
├── P25ActivateOptionsControl.cs
├── P25ActivateOptionsControl.resx
├── P25DESEncryptionMethodForm.Designer.cs
├── P25DESEncryptionMethodForm.cs
├── P25DESEncryptionMethodForm.resx
├── P25DESEncryptionRow.cs
├── P25EncryptionRow.cs
├── P25SelectedActivateOptionsEnum.cs
├── Program.cs
├── Project.cs
├── Properties
├── AssemblyInfo.cs
├── Resources.Designer.cs
├── Resources.resx
├── Settings.Designer.cs
└── Settings.settings
├── ProtocolEnum.cs
├── Scanner.cs
├── ScannerAttribute.cs
├── ScannerBaseModelEnum.cs
├── ScannerForm.Designer.cs
├── ScannerForm.cs
├── ScannerForm.resx
├── ScannerListForm.Designer.cs
├── ScannerListForm.cs
├── ScannerListForm.resx
├── ScannerModelEnum.cs
├── SelectEncryptionMethodForm.Designer.cs
├── SelectEncryptionMethodForm.cs
├── SelectEncryptionMethodForm.resx
├── TyteraBPEncryptionMethodForm.Designer.cs
├── TyteraBPEncryptionMethodForm.cs
├── TyteraBPEncryptionMethodForm.resx
├── TyteraBPEncryptionRow.cs
├── TyteraEPEncryptionMethodForm.Designer.cs
├── TyteraEPEncryptionMethodForm.cs
├── TyteraEPEncryptionMethodForm.resx
├── TyteraEPEncryptionRow.cs
├── Utils.cs
├── app.ico
├── fakesign.snk
├── images
├── JD.png
├── add.png
├── delete.png
├── down.png
├── duplicate.png
├── new.png
├── open.png
├── save.png
└── up.png
└── packages.config
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 |
24 | # Visual Studo 2015 cache/options directory
25 | .vs/
26 |
27 | # MSTest test Results
28 | [Tt]est[Rr]esult*/
29 | [Bb]uild[Ll]og.*
30 |
31 | # NUNIT
32 | *.VisualState.xml
33 | TestResult.xml
34 |
35 | # Build Results of an ATL Project
36 | [Dd]ebugPS/
37 | [Rr]eleasePS/
38 | dlldata.c
39 |
40 | *_i.c
41 | *_p.c
42 | *_i.h
43 | *.ilk
44 | *.meta
45 | *.obj
46 | *.pch
47 | *.pdb
48 | *.pgc
49 | *.pgd
50 | *.rsp
51 | *.sbr
52 | *.tlb
53 | *.tli
54 | *.tlh
55 | *.tmp
56 | *.tmp_proj
57 | *.log
58 | *.vspscc
59 | *.vssscc
60 | .builds
61 | *.pidb
62 | *.svclog
63 | *.scc
64 |
65 | # Chutzpah Test files
66 | _Chutzpah*
67 |
68 | # Visual C++ cache files
69 | ipch/
70 | *.aps
71 | *.ncb
72 | *.opensdf
73 | *.sdf
74 | *.cachefile
75 |
76 | # Visual Studio profiler
77 | *.psess
78 | *.vsp
79 | *.vspx
80 |
81 | # TFS 2012 Local Workspace
82 | $tf/
83 |
84 | # Guidance Automation Toolkit
85 | *.gpState
86 |
87 | # ReSharper is a .NET coding add-in
88 | _ReSharper*/
89 | *.[Rr]e[Ss]harper
90 | *.DotSettings.user
91 |
92 | # JustCode is a .NET coding addin-in
93 | .JustCode
94 |
95 | # TeamCity is a build add-in
96 | _TeamCity*
97 |
98 | # DotCover is a Code Coverage Tool
99 | *.dotCover
100 |
101 | # NCrunch
102 | _NCrunch_*
103 | .*crunch*.local.xml
104 |
105 | # MightyMoose
106 | *.mm.*
107 | AutoTest.Net/
108 |
109 | # Web workbench (sass)
110 | .sass-cache/
111 |
112 | # Installshield output folder
113 | [Ee]xpress/
114 |
115 | # DocProject is a documentation generator add-in
116 | DocProject/buildhelp/
117 | DocProject/Help/*.HxT
118 | DocProject/Help/*.HxC
119 | DocProject/Help/*.hhc
120 | DocProject/Help/*.hhk
121 | DocProject/Help/*.hhp
122 | DocProject/Help/Html2
123 | DocProject/Help/html
124 |
125 | # Click-Once directory
126 | publish/
127 |
128 | # Publish Web Output
129 | *.[Pp]ublish.xml
130 | *.azurePubxml
131 | # TODO: Comment the next line if you want to checkin your web deploy settings
132 | # but database connection strings (with potential passwords) will be unencrypted
133 | *.pubxml
134 | *.publishproj
135 |
136 | # NuGet Packages
137 | *.nupkg
138 | # The packages folder can be ignored because of Package Restore
139 | **/packages/*
140 | # except build/, which is used as an MSBuild target.
141 | !**/packages/build/
142 | # Uncomment if necessary however generally it will be regenerated when needed
143 | #!**/packages/repositories.config
144 |
145 | # Windows Azure Build Output
146 | csx/
147 | *.build.csdef
148 |
149 | # Windows Store app package directory
150 | AppPackages/
151 |
152 | # Others
153 | *.[Cc]ache
154 | ClientBin/
155 | [Ss]tyle[Cc]op.*
156 | ~$*
157 | *~
158 | *.dbmdl
159 | *.dbproj.schemaview
160 | *.publishsettings
161 | node_modules/
162 | bower_components/
163 | *.exe
164 | build/*.zip
165 | build/temp
166 |
167 | # RIA/Silverlight projects
168 | Generated_Code/
169 |
170 | # Backup & report files from converting an old project file
171 | # to a newer Visual Studio version. Backup files are not needed,
172 | # because we have git ;-)
173 | _UpgradeReport_Files/
174 | Backup*/
175 | UpgradeLog*.XML
176 | UpgradeLog*.htm
177 |
178 | # SQL Server files
179 | *.mdf
180 | *.ldf
181 |
182 | # Business Intelligence projects
183 | *.rdl.data
184 | *.bim.layout
185 | *.bim_*.settings
186 |
187 | # Microsoft Fakes
188 | FakesAssemblies/
189 |
190 | # Node.js Tools for Visual Studio
191 | .ntvs_analysis.dat
192 |
193 | # Visual Studio 6 build log
194 | *.plg
195 |
196 | # Visual Studio 6 workspace options file
197 | *.opt
198 | /build/temp
199 | /build/artifacts
200 | /src/main/Properties/launchSettings.json
201 | /src/main.lib/Properties/launchSettings.json
202 |
203 | # Rider
204 | .idea/
--------------------------------------------------------------------------------
/DEBUG.md:
--------------------------------------------------------------------------------
1 | # Debug Logs
2 |
3 | For more precise determination of the parameters of voice traffic decryption activation, control info is output to the scanner debug logs.
4 |
5 | You can activate debug logging via the scanner menu Settings - Set Debug Logs Mode - SD Card (File).
6 |
7 | The generated debug logs can then be found on the scanner SD Card in the /BCDx36HP/debug/ directory.
8 |
9 | #### Debug Log String Format
10 |
11 | ##### MI
12 |
13 | ```
14 | 0066766 :MI 0 9974B94B 9974B94B 0 21 01
15 | 1 2 3 4 5 6 7 8
16 | ```
17 | The debug output string consists of 8 fields separated by a space.
18 |
19 | ```
20 | 1 - Time stamp in microseconds
21 | 2 - Signature ":MI" - IV and addition info
22 | 3 - BPTC error. If =0 then assign new IV
23 | 4 - Calculated IV (by Motorola LFSR algo)
24 | 5 - Extracted IV from control frames. For Moto EP must be Field(4) = Field (5)
25 | 6 - BPTC16 error. If !=0 and known AlgoID then assign new encryption params
26 | 7 - AlgoID
27 | 21 - RC4
28 | 22 - DES
29 | 24 - AES128
30 | 25 - AES256
31 | 8 - KeyID
32 | ```
33 | ##### N0 - NXDN Control and Voice Info
34 |
35 | ```
36 | 0067268 :N0 04307750 02 04 02 02 00 00 0000 00000000 00000003 D 1 01 28139 0 105D02A0246A00 90FF381CC07A00 C32EA656008700 98B3C2806C4200
37 | 1 2 3 4 5 6 7 8 9 10 11 12 131415 16 1718 19 20 21
38 | ```
39 | The debug output string consists of 21 fields separated by a space.
40 |
41 | ```
42 | 1 - Time stamp in microseconds
43 | 2 - Signature ":N0" - NXDN protocol, version 0
44 | 3 - Frequency in 100 Hz scale (DEC)
45 | 4 - NXDN Frame Type
46 | Range: 0-8
47 | 5 - NXDN Data Type
48 | 0 - SACCH
49 | 1,5,6 - FACCH1
50 | 2 - FACCH2
51 | 3 - CAC
52 | 6 - NXDN Vocoder Mode
53 | Range: 0-3
54 | 7 - RAN
55 | 8 - AREA
56 | 9 - SITE
57 | 10 - SYSTEM
58 | 11 - GROUP ID
59 | 12 - UID
60 | 13 - Voice traffic decryption identifier
61 | D - Parameters are not defined
62 | U - Protocol unlocked
63 | A - Allowed
64 | S - Time session restriction
65 | 14 - NXDN Cypher Type
66 | 0 - Non Ciphered
67 | 1 - Scrambler
68 | 2 - Des
69 | 3 - Aes
70 | 15 - Key ID
71 | 16 - NXDN Current Scrambler Key (DEC)
72 | 17 - NXDN Scrambler Key Offset
73 | Inner control data
74 | 18 - Voice packet 0, 49 bits (HEX)
75 | 19 - Voice packet 1, 49 bits (HEX)
76 | 20 - Voice packet 2, 49 bits (HEX)
77 | 21 - Voice packet 3, 49 bits (HEX)
78 | ```
79 |
80 | ##### D1 - DMR Control and Voice Info
81 |
82 | ```
83 | 0201377 :D1 04404400 1 1F 0 01 C 8 68 0000214D 002628B2 0000 1 1 0 0000 0000 0000 D E1F9DA3443BF80 27C2718F2D3600 2F18B5E5C67080
84 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14151617 18 19 2021 22 23
85 | ```
86 |
87 | The debug output string consists of 23 fields separated by a space.
88 |
89 | ```
90 | 1 - Time stamp in microseconds
91 | 2 - Signature ":D1" - DMR protocol, version 1
92 | 3 - Frequency in 100 Hz scale (DEC)
93 | 4 - Trunk system type
94 | 0 - DMR One?
95 | 1 - Simple DMR
96 | 2 - Capacity+
97 | 3 - Connect+
98 | 4 - DMR Tier III
99 | 5 - Hytera XPT
100 | 5 - Data type
101 | 0 - PI Header
102 | 1 - Voice LC Header
103 | 2 - Terminator with LC
104 | 3 - CSBK
105 | 4 - MBC Header
106 | 5 - MBC Continuation
107 | 6 - Data Header
108 | 7 - Rate 1/2 Data
109 | 8 - Rate 3/4 Data
110 | 9 - Idle
111 | A - Rate 1 Data
112 | B - Unified Single Block Data
113 | C - Reserved for future use
114 | D - Reserved for future use
115 | E - Reserved for future use
116 | F - Reserved for future use
117 | 1E - ?
118 | 1F - ?
119 | 6 - TDMA channel number
120 | 7 - Call type (HEX)
121 | 8 - Color code (HEX)
122 | 0 - F
123 | 9 - Superframe number (HEX)
124 | 0 - B
125 | 10 - EMB FID manufacturer identifier (HEX)
126 | 10 - Motorola
127 | 68 - Hytera
128 | 11 - EMB TGID talkgroup number (HEX)
129 | 12 - EMB User ID (HEX)
130 | 13 - C-CH
131 | 14 - Encrypt Value
132 | 1 - Non encrypted
133 | 2 - Encrypted
134 | 15 - Privacy
135 | 16 - EMB Privacy
136 | 17 - SLC LCN
137 | 18 - SLC NID
138 | 19 - SLC SID
139 | 20 - Voice traffic decryption identifier
140 | D - Parameters are not defined
141 | U - Protocol unlocked
142 | A - Allowed
143 | S - Time session restriction
144 | 21 - Voice packet 0, 49 bits (HEX)
145 | 22 - Voice packet 1, 49 bits (HEX)
146 | 23 - Voice packet 2, 49 bits (HEX)
147 | ```
148 |
149 |
150 |
--------------------------------------------------------------------------------
/img/add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/add.png
--------------------------------------------------------------------------------
/img/crypto0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/crypto0.jpg
--------------------------------------------------------------------------------
/img/crypto1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/crypto1.jpg
--------------------------------------------------------------------------------
/img/crypto2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/crypto2.jpg
--------------------------------------------------------------------------------
/img/crypto3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/crypto3.jpg
--------------------------------------------------------------------------------
/img/crypto4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/crypto4.jpg
--------------------------------------------------------------------------------
/img/crypto5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/crypto5.jpg
--------------------------------------------------------------------------------
/img/crypto6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/crypto6.jpg
--------------------------------------------------------------------------------
/img/crypto7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/crypto7.jpg
--------------------------------------------------------------------------------
/img/crypto8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/crypto8.jpg
--------------------------------------------------------------------------------
/img/crypto9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/crypto9.jpg
--------------------------------------------------------------------------------
/img/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/delete.png
--------------------------------------------------------------------------------
/img/down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/down.png
--------------------------------------------------------------------------------
/img/duplicate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/duplicate.png
--------------------------------------------------------------------------------
/img/filtering.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/filtering.png
--------------------------------------------------------------------------------
/img/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/image.png
--------------------------------------------------------------------------------
/img/man0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man0.png
--------------------------------------------------------------------------------
/img/man1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man1.png
--------------------------------------------------------------------------------
/img/man10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man10.png
--------------------------------------------------------------------------------
/img/man11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man11.png
--------------------------------------------------------------------------------
/img/man2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man2.png
--------------------------------------------------------------------------------
/img/man3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man3.png
--------------------------------------------------------------------------------
/img/man4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man4.png
--------------------------------------------------------------------------------
/img/man5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man5.png
--------------------------------------------------------------------------------
/img/man6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man6.png
--------------------------------------------------------------------------------
/img/man7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man7.png
--------------------------------------------------------------------------------
/img/man8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man8.png
--------------------------------------------------------------------------------
/img/man9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/man9.png
--------------------------------------------------------------------------------
/img/new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/new.png
--------------------------------------------------------------------------------
/img/open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/open.png
--------------------------------------------------------------------------------
/img/save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/save.png
--------------------------------------------------------------------------------
/img/up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/up.png
--------------------------------------------------------------------------------
/img/wallet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/img/wallet.png
--------------------------------------------------------------------------------
/src/AboutForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Reflection;
4 | using System.Windows.Forms;
5 |
6 | namespace CFT
7 | {
8 | public partial class AboutForm : Form
9 | {
10 | public AboutForm()
11 | {
12 | InitializeComponent();
13 | var fvi = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
14 | lblVersion.Text = $"v{fvi.FileVersion}";
15 | }
16 |
17 | private void linkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
18 | {
19 | var target = (sender as LinkLabel).Text;
20 | if (target.IndexOf("@") != -1)
21 | target = "email:" + target;
22 | Process.Start(target);
23 | }
24 |
25 | private void btnClose_Click(object sender, EventArgs e)
26 | {
27 | Close();
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/AboutForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/AnytoneEncEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class AnytoneEncEncryptionMethodForm : Form
7 | {
8 | public AnytoneEncEncryptionRow EncryptionRow { get; private set; }
9 |
10 | public bool IsBatchMode { get; private set; }
11 |
12 | public AnytoneEncEncryptionMethodForm(AnytoneEncEncryptionRow row = null, bool batchMode = false)
13 | {
14 | InitializeComponent();
15 |
16 | optionsControl.OptionChanged += OptionsControl_OptionChanged;
17 |
18 | IsBatchMode = batchMode;
19 | if (IsBatchMode)
20 | {
21 | Text += " (Batch mode)";
22 | tbFrequency.Enabled = false;
23 | tbNotes.Enabled = false;
24 | }
25 |
26 | if (row == null)
27 | {
28 | EncryptionRow = new AnytoneEncEncryptionRow();
29 | if (!IsBatchMode)
30 | tbFrequency.Text = Utils.GetFrequencyString(145500000);
31 | optionsControl.SetOptions(null);
32 | }
33 | else
34 | {
35 | EncryptionRow = row;
36 | if (!IsBatchMode)
37 | tbFrequency.Text = Utils.GetFrequencyString(row.Frequency);
38 | optionsControl.SetOptions(row.ActivateOptions);
39 | nudKey.Value = row.Key;
40 | tbNotes.Text = row.Notes;
41 | }
42 | OptionsControl_OptionChanged(this, null);
43 | }
44 |
45 | private void OptionsControl_OptionChanged(object sender, EventArgs e)
46 | {
47 | tbFrequency.Enabled = optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.Frequency);
48 | nudKey.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
49 | }
50 |
51 | private void btnOK_Click(object sender, EventArgs e)
52 | {
53 | string errorStr;
54 |
55 | if (optionsControl.IsExistErrors(out errorStr))
56 | {
57 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
58 | return;
59 | }
60 |
61 | uint freq = 0;
62 | if (!IsBatchMode && !Utils.ParseFrequency(tbFrequency.Text, out freq, out errorStr))
63 | {
64 | tbFrequency.Focus();
65 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
66 | return;
67 | }
68 |
69 | EncryptionRow.Frequency = freq;
70 | EncryptionRow.ActivateOptions = optionsControl.Options;
71 | EncryptionRow.Key = (ushort)nudKey.Value;
72 | EncryptionRow.Notes = tbNotes.Text.Trim();
73 |
74 | DialogResult = DialogResult.OK;
75 | Close();
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/AnytoneEncEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("Anytone Enc")]
7 |
8 | [Serializable]
9 | public class AnytoneEncEncryptionRow : DmrEncryptionRow
10 | {
11 | public ushort Key { get; set; }
12 |
13 | public AnytoneEncEncryptionRow()
14 | {
15 | Key = 1;
16 | ActivateOptions = new DmrActivateOptions();
17 | }
18 |
19 | [JsonIgnore]
20 | public override string Description
21 | {
22 | get
23 | {
24 | if (ActivateOptions.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute))
25 | return $"Anytone Enc: {ActivateOptions}";
26 | else
27 | return $"Anytone Enc: Key({Key:X04}) {ActivateOptions}";
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/BaseEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CFT
4 | {
5 | [Serializable]
6 | public abstract class BaseEncryptionRow : IEncryptionRow
7 | {
8 | public uint Frequency { get; set; }
9 |
10 | public string Notes { get; set; }
11 |
12 | public abstract ProtocolEnum Protocol { get; }
13 |
14 | public abstract string Description { get; }
15 |
16 | public abstract bool IsFrequencyNeed { get; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/CFT.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.8.34601.278
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CFT", "CFT.csproj", "{5ABFC518-FDBC-4864-B546-AE52ABA4BF63}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {5ABFC518-FDBC-4864-B546-AE52ABA4BF63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {5ABFC518-FDBC-4864-B546-AE52ABA4BF63}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {5ABFC518-FDBC-4864-B546-AE52ABA4BF63}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {5ABFC518-FDBC-4864-B546-AE52ABA4BF63}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {07B3180A-E998-4B5E-894A-9491D3F671FA}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/src/DebugLogsFilteringForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Windows.Forms;
4 |
5 | namespace CFT
6 | {
7 | public partial class DebugLogsFilteringForm : Form
8 | {
9 | static readonly string [] DEBUG_LINE_SIGNATURES = { ":D", ":B", ":N", ":R", ":P", ":C", ":A", ":M" };
10 |
11 | public DebugLogsFilteringForm()
12 | {
13 | InitializeComponent();
14 | UpdateControls();
15 | }
16 |
17 | private void UpdateControls()
18 | {
19 | nudTime.Enabled = cbInsertSpaceLine.Checked;
20 | btnOk.Enabled = !string.IsNullOrEmpty(tbDebugLogFilename.Text);
21 | }
22 |
23 | private void cbInsertSpaceLine_CheckedChanged(object sender, EventArgs e)
24 | {
25 | UpdateControls();
26 | }
27 |
28 | private void btnOk_Click(object sender, EventArgs e)
29 | {
30 | var count = 0;
31 | try
32 | {
33 | uint previousTick = 0;
34 |
35 | var outputFileName = Path.ChangeExtension(tbDebugLogFilename.Text, "filtered.txt");
36 |
37 | using (TextReader tr = new StreamReader(File.Open(tbDebugLogFilename.Text, FileMode.Open, FileAccess.Read, FileShare.Read)))
38 | using (TextWriter tw = new StreamWriter(File.Open(outputFileName, FileMode.Create, FileAccess.Write, FileShare.Write)))
39 | {
40 | string line;
41 | while ((line = tr.ReadLine()) != null)
42 | {
43 | count++;
44 |
45 | var foundSignature = false;
46 | foreach (var sig in DEBUG_LINE_SIGNATURES)
47 | {
48 | if (line.Contains(sig))
49 | {
50 | foundSignature = true;
51 | break;
52 | }
53 | }
54 | if (!foundSignature)
55 | continue;
56 |
57 | if (cbInsertSpaceLine.Checked)
58 | {
59 | var token = line.Split(' ');
60 |
61 | if (uint.TryParse(token[0], out uint res))
62 | {
63 | if (res - previousTick > nudTime.Value)
64 | tw.WriteLine();
65 | previousTick = res;
66 | }
67 | }
68 | tw.WriteLine(line);
69 | }
70 | }
71 | MessageBox.Show("Done.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
72 | }
73 | catch(Exception ex)
74 | {
75 | MessageBox.Show($"Error in the line {count}\r\n{ex.Message}\r\n{ex.StackTrace}", "Error");
76 | }
77 | }
78 |
79 | private void btnDebugLogFileSelect_Click(object sender, EventArgs e)
80 | {
81 | try
82 | {
83 | OpenFileDialog dlg = new OpenFileDialog();
84 | dlg.Filter = "Debug Log Files (*.txt)|*.txt|All Files|*.*";
85 | dlg.Multiselect = false;
86 | dlg.RestoreDirectory = true;
87 | if (dlg.ShowDialog() == DialogResult.OK)
88 | {
89 | tbDebugLogFilename.Text = dlg.FileName;
90 | UpdateControls();
91 | }
92 | }
93 | catch (Exception ex)
94 | {
95 | MessageBox.Show(ex.Message + ex.StackTrace, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
96 | }
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/DebugLogsFilteringForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/DisplayAdditionalInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CFT
4 | {
5 | [Serializable]
6 | public class DisplayAdditionalInfo
7 | {
8 | public DisplayAdditionalInfoValuesEnum Line0 { get; set; } = DisplayAdditionalInfoValuesEnum.Default;
9 | public DisplayAdditionalInfoValuesEnum Line1 { get; set; } = DisplayAdditionalInfoValuesEnum.Default;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/DisplayAdditionalInfoForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Windows.Forms;
4 |
5 | namespace CFT
6 | {
7 | public partial class DisplayAdditionalInfoForm : Form
8 | {
9 | public DisplayAdditionalInfo DisplayAdditionalInfo { get; private set; }
10 | public ScannerModelEnum Model { get; private set; }
11 |
12 | public DisplayAdditionalInfoForm(ScannerModelEnum model, DisplayAdditionalInfo additionalInfo)
13 | {
14 | InitializeComponent();
15 |
16 | Model = model;
17 | DisplayAdditionalInfo = additionalInfo;
18 |
19 | if (Scanner.GetBaseModel(model) == ScannerBaseModelEnum.BCD)
20 | {
21 | FillComboBoxData(cbLine0);
22 | FillComboBoxData(cbLine1);
23 |
24 | if (DisplayAdditionalInfo != null)
25 | {
26 | if (!Utils.SetComboBoxData(cbLine0, DisplayAdditionalInfo.Line0))
27 | Utils.SetComboBoxData(cbLine0, DisplayAdditionalInfoValuesEnum.Default);
28 | if (!Utils.SetComboBoxData(cbLine1, DisplayAdditionalInfo.Line1))
29 | Utils.SetComboBoxData(cbLine1, DisplayAdditionalInfoValuesEnum.Default);
30 | }
31 | else
32 | {
33 | Utils.SetComboBoxData(cbLine0, DisplayAdditionalInfoValuesEnum.Default);
34 | Utils.SetComboBoxData(cbLine1, DisplayAdditionalInfoValuesEnum.Default);
35 | }
36 | }
37 | else
38 | {
39 | lblLine0.Text = "ALGO";
40 | lblLine1.Visible = false;
41 | cbLine1.Visible = false;
42 | cbLine0.Items.Add(new DisplayTagObject(DisplayAdditionalInfoValuesEnum.MfidEncAlgoKeyIdHex));
43 | cbLine0.Items.Add(new DisplayTagObject(DisplayAdditionalInfoValuesEnum.MfidEncAlgoKeyIdDec));
44 |
45 | if (DisplayAdditionalInfo != null)
46 | {
47 | if (DisplayAdditionalInfo.Line0 == DisplayAdditionalInfoValuesEnum.MfidEncAlgoKeyIdDec)
48 | Utils.SetComboBoxData(cbLine0, DisplayAdditionalInfoValuesEnum.MfidEncAlgoKeyIdDec);
49 | else
50 | Utils.SetComboBoxData(cbLine0, DisplayAdditionalInfoValuesEnum.MfidEncAlgoKeyIdHex);
51 | }
52 | else
53 | {
54 | Utils.SetComboBoxData(cbLine0, DisplayAdditionalInfoValuesEnum.MfidEncAlgoKeyIdHex);
55 | }
56 | }
57 | }
58 |
59 | public void FillComboBoxData(ComboBox cb)
60 | {
61 | cb.Items.Clear();
62 | foreach (DisplayAdditionalInfoValuesEnum item in Enum.GetValues(typeof(DisplayAdditionalInfoValuesEnum)))
63 | {
64 | cb.Items.Add(new DisplayTagObject(item));
65 | }
66 | }
67 |
68 | private void btnOk_Click(object sender, EventArgs e)
69 | {
70 | if (DisplayAdditionalInfo == null)
71 | DisplayAdditionalInfo = new DisplayAdditionalInfo();
72 |
73 | DisplayAdditionalInfo.Line0 = (DisplayAdditionalInfoValuesEnum)Utils.GetComboBoxData(cbLine0.SelectedItem);
74 | if (Scanner.GetBaseModel(Model) == ScannerBaseModelEnum.BCD)
75 | {
76 | DisplayAdditionalInfo.Line1 = (DisplayAdditionalInfoValuesEnum)Utils.GetComboBoxData(cbLine1.SelectedItem);
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/DisplayAdditionalInfoForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/DisplayAdditionalInfoValuesEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum DisplayAdditionalInfoValuesEnum
4 | {
5 | [DisplayName("Default")]
6 | Default = 0,
7 | [DisplayName("RSSI")]
8 | RSSI = 1,
9 | [DisplayName("MFID, Encrypton Algo and KeyID (HEX)")]
10 | MfidEncAlgoKeyIdHex = 2,
11 | [DisplayName("MFID, Encrypton Algo and KeyID (DEC)")]
12 | MfidEncAlgoKeyIdDec = 3
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/DisplayNameAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CFT
4 | {
5 | [AttributeUsage(AttributeTargets.All)]
6 | public class DisplayNameAttribute : System.ComponentModel.DisplayNameAttribute
7 | {
8 | private readonly string _name;
9 | public DisplayNameAttribute(string name)
10 | {
11 | _name = name;
12 | }
13 |
14 | public string Name { get { return _name; } }
15 |
16 | public static string GetName(object o)
17 | {
18 | if (o == null) return string.Empty;
19 |
20 | var t = o.GetType();
21 | if (t.IsEnum)
22 | {
23 | var fi = t.GetFields();
24 | foreach (var fieldInfo in fi)
25 | {
26 | if (fieldInfo.Name == o.ToString())
27 | {
28 | var a = (DisplayNameAttribute)GetCustomAttribute(fieldInfo, typeof(DisplayNameAttribute));
29 | return a == null ? fieldInfo.Name : a.Name;
30 | }
31 | }
32 | }
33 | else
34 | {
35 | var a = (DisplayNameAttribute)GetCustomAttribute(t, typeof(DisplayNameAttribute));
36 | if (a != null)
37 | return a.Name;
38 |
39 | }
40 | return string.Empty;
41 | }
42 |
43 | public static string GetName(Type t)
44 | {
45 | if (t == null) return string.Empty;
46 |
47 | var a = (DisplayNameAttribute)GetCustomAttribute(t, typeof(DisplayNameAttribute));
48 | return a != null ? a.Name : string.Empty;
49 | }
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/DisplayTagObject.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public class DisplayTagObject
4 | {
5 | public string Name { get; private set; }
6 | public object Tag { get; set; }
7 |
8 | public DisplayTagObject(object o)
9 | {
10 | Tag = o;
11 | Name = DisplayNameAttribute.GetName(o);
12 | }
13 |
14 | public override string ToString()
15 | {
16 | return string.IsNullOrEmpty(Name) ? Tag.ToString() : Name;
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/src/DmrActivateOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace CFT
5 | {
6 | [Serializable]
7 | public class DmrActivateOptions : IActivateOptions
8 | {
9 | public DmrSelectedActivateOptionsEnum Options { get; set; }
10 | public DmrTrunkSystemEnum TrunkSystem { get; set; }
11 | public DmrMfidEnum MFID { get; set; }
12 | public DmrColorCodeEnum ColorCode { get; set; }
13 | public uint TGID { get; set; }
14 | public DmrTimeSlotEnum TimeSlot { get; set; }
15 | public DmrEncyptionValueEnum EncryptionValue { get; set; }
16 |
17 | public byte KeyId { get; set; }
18 |
19 | public DmrActivateOptions()
20 | {
21 | Activate(DmrSelectedActivateOptionsEnum.Frequency);
22 | }
23 |
24 | public bool IsActivated(DmrSelectedActivateOptionsEnum option)
25 | {
26 | return (Options & option) == option;
27 | }
28 |
29 | public void Activate(DmrSelectedActivateOptionsEnum option)
30 | {
31 | Options |= option;
32 | }
33 |
34 | public override string ToString()
35 | {
36 | var sb = new StringBuilder();
37 | if (IsActivated(DmrSelectedActivateOptionsEnum.TrunkSystem))
38 | sb.Append($"Trunk({DisplayNameAttribute.GetName(TrunkSystem)}) ");
39 | if (IsActivated(DmrSelectedActivateOptionsEnum.TGID))
40 | sb.Append($"TGID({TGID}) ");
41 | if (IsActivated(DmrSelectedActivateOptionsEnum.MFID))
42 | sb.Append($"MFID({DisplayNameAttribute.GetName(MFID)}) ");
43 | if (IsActivated(DmrSelectedActivateOptionsEnum.ColorCode))
44 | sb.Append($"CC({(int)ColorCode}) ");
45 | if (IsActivated(DmrSelectedActivateOptionsEnum.KeyId))
46 | sb.Append($"KeyID({KeyId}) ");
47 | if (IsActivated(DmrSelectedActivateOptionsEnum.ForceMute))
48 | sb.Append($"Force Mute");
49 | return sb.ToString();
50 | }
51 |
52 | internal void Deactivate(DmrSelectedActivateOptionsEnum option)
53 | {
54 | Options &= ~option;
55 | }
56 |
57 | public int CompareTo(object obj)
58 | {
59 | var o = obj as DmrActivateOptions;
60 | if (o == null)
61 | return 1;
62 |
63 | if (o.Options != Options)
64 | return 1;
65 |
66 | if (IsActivated(DmrSelectedActivateOptionsEnum.TrunkSystem) &&
67 | o.TrunkSystem != TrunkSystem)
68 | return 1;
69 |
70 | if (IsActivated(DmrSelectedActivateOptionsEnum.MFID) &&
71 | o.MFID != MFID)
72 | return 1;
73 |
74 | if (IsActivated(DmrSelectedActivateOptionsEnum.ColorCode) &&
75 | o.ColorCode != ColorCode)
76 | return 1;
77 |
78 | if (IsActivated(DmrSelectedActivateOptionsEnum.TGID) &&
79 | o.TGID != TGID)
80 | return 1;
81 |
82 | if (IsActivated(DmrSelectedActivateOptionsEnum.TimeSlot) &&
83 | o.TimeSlot != TimeSlot)
84 | return 1;
85 |
86 | if (IsActivated(DmrSelectedActivateOptionsEnum.EncryptValue) &&
87 | o.EncryptionValue != EncryptionValue)
88 | return 1;
89 |
90 | if (IsActivated(DmrSelectedActivateOptionsEnum.KeyId) &&
91 | o.KeyId != KeyId)
92 | return 1;
93 |
94 | return 0;
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/DmrAesEncryptionMethodForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/DmrAesEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("DMR AES")]
7 | [Serializable]
8 | public class DmrAesEncryptionRow : DmrEncryptionRow
9 | {
10 | public const int KEY_SIZE = 32;
11 | public ushort KeyLength { get; set; }
12 |
13 | public byte[] Key { get; set; }
14 |
15 | [JsonIgnore]
16 | public override string Description => $"DMR AES: KeyLen({KeyLength}) {ActivateOptions}";
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/DmrAesKeyLengthEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum DmrAesKeyLengthEnum
4 | {
5 | [DisplayName("128 bits")]
6 | L128 = 128,
7 | [DisplayName("192 bits")]
8 | L192 = 192,
9 | [DisplayName("256 bits")]
10 | L256 = 256
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/DmrColorCodeEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum DmrColorCodeEnum
4 | {
5 | [DisplayName("CC 0")]
6 | CC0 = 0,
7 | [DisplayName("CC 1")]
8 | CC1 = 1,
9 | [DisplayName("CC 2")]
10 | CC2 = 2,
11 | [DisplayName("CC 3")]
12 | CC3 = 3,
13 | [DisplayName("CC 4")]
14 | CC4 = 4,
15 | [DisplayName("CC 5")]
16 | CC5 = 5,
17 | [DisplayName("CC 6")]
18 | CC6 = 6,
19 | [DisplayName("CC 7")]
20 | CC7 = 7,
21 | [DisplayName("CC 8")]
22 | CC8 = 8,
23 | [DisplayName("CC 9")]
24 | CC9 = 9,
25 | [DisplayName("CC 10")]
26 | CC10 = 10,
27 | [DisplayName("CC 11")]
28 | CC11 = 11,
29 | [DisplayName("CC 12")]
30 | CC12 = 12,
31 | [DisplayName("CC 13")]
32 | CC13 = 13,
33 | [DisplayName("CC 14")]
34 | CC14 = 14,
35 | [DisplayName("CC 15")]
36 | CC15 = 15
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/DmrEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [Serializable]
7 | public abstract class DmrEncryptionRow : BaseEncryptionRow
8 | {
9 | [JsonIgnore]
10 | public override ProtocolEnum Protocol => ProtocolEnum.DMR;
11 |
12 | public DmrActivateOptions ActivateOptions { get; set; }
13 | public override bool IsFrequencyNeed => ActivateOptions == null ? true : ActivateOptions.IsActivated(DmrSelectedActivateOptionsEnum.Frequency);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/DmrEncyptionValueEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum DmrEncyptionValueEnum
4 | {
5 | [DisplayName("Non Encrypted")]
6 | Value1 = 1,
7 | [DisplayName("Encrypted")]
8 | Value2 = 2
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/DmrMfidEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum DmrMfidEnum
4 | {
5 | [DisplayName("Unknown (0x00)")]
6 | Unknown = 0x00,
7 | [DisplayName("Motorola")]
8 | Motorola = 0x10,
9 | [DisplayName("Hytera")]
10 | Hytera = 0x68
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/DmrSelectedActivateOptionsEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | [System.Flags]
4 | public enum DmrSelectedActivateOptionsEnum : uint
5 | {
6 | TrunkSystem = 1 << 0,
7 | MFID = 1 << 1,
8 | Frequency = 1 << 2,
9 | ColorCode = 1 << 3,
10 | TGID = 1 << 4,
11 | TimeSlot = 1 << 5,
12 | EncryptValue = 1 << 6,
13 | KeyId = 1 << 7,
14 |
15 | ForceMute = 1 << 15
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/DmrTimeSlotEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum DmrTimeSlotEnum
4 | {
5 | [DisplayName("Slot 1")]
6 | Slot1 = 0,
7 | [DisplayName("Slot 2")]
8 | Slot2 = 1
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/DmrTrunkSystemEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum DmrTrunkSystemEnum
4 | {
5 | [DisplayName("DMR MS")]
6 | DMRMS = 0,
7 | [DisplayName("Simple DMR")]
8 | DMR = 1,
9 | [DisplayName("Capacity+")]
10 | CAP = 2,
11 | [DisplayName("Connect+")]
12 | CON = 3,
13 | [DisplayName("DMR Tier III")]
14 | DT3 = 4,
15 | [DisplayName("Hytera XPT")]
16 | XPT = 5
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/DsdImport.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Windows.Forms;
5 |
6 | namespace CFT
7 | {
8 | public class DsdImport
9 | {
10 | public static List Import(string filename)
11 | {
12 | var res = new List();
13 | var count = 0;
14 | try
15 | {
16 | using (TextReader tr = new StreamReader(File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read)))
17 | {
18 | count++;
19 |
20 | string line;
21 | while ((line = tr.ReadLine()) != null)
22 | {
23 | var commentIndex = line.IndexOf(";");
24 | if (commentIndex != -1)
25 | line = line.Substring(0, commentIndex).Trim();
26 |
27 | if (string.IsNullOrEmpty(line.Trim()))
28 | continue;
29 |
30 | var token = line.Split(',');
31 | if (token.Length != 7)
32 | throw new Exception($"Wrong item count in row: {token.Length}");
33 | var item = new ImportItem();
34 | if (!Utils.ParseFrequency(token[4], out uint freq, out string err))
35 | throw new Exception(err);
36 | item.Frequency = freq;
37 | item.Notes = $"{token[0]} {token[1]} {token[2]} {token[3]}";
38 | res.Add(item);
39 | }
40 | }
41 | }
42 | catch (Exception ex)
43 | {
44 | MessageBox.Show($"Error in the line {count}\r\n{ex.Message}\r\n{ex.StackTrace}", "Error");
45 | res = null;
46 | }
47 |
48 | return res;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/EncryptionMethodEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum EncryptionMethodEnum
4 | {
5 | [DisplayName("Motorola BP")]
6 | MotorolaBP = 1,
7 | [DisplayName("Hytera BP")]
8 | HyteraBP = 2,
9 | [DisplayName("Nxdn Scrambler")]
10 | NxdnScrambler = 3,
11 | [DisplayName("Motorola EP")]
12 | MotorolaEP = 4,
13 | [DisplayName("Anytone Enc")]
14 | AnytoneEnc = 5,
15 | [DisplayName("P25 ADP")]
16 | P25ADP = 6,
17 | [DisplayName("P25 DES")]
18 | P25DES = 7,
19 | [DisplayName("Tytera EP")]
20 | TyteraEP = 8,
21 | [DisplayName("DMR AES")]
22 | DMRAES = 9,
23 | [DisplayName("Tytera BP")]
24 | TyteraBP = 10,
25 | [DisplayName("Kirisun BP")]
26 | KirisunBP = 11,
27 | [DisplayName("Hytera EP")]
28 | HyteraEP = 12,
29 | [DisplayName("P25 AES")]
30 | P25AES = 13
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/HyteraBPEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class HyteraBPEncryptionMethodForm : Form
7 | {
8 | public HyteraBPEncryptionRow EncryptionRow { get; private set; }
9 | public bool IsBatchMode { get; private set; }
10 |
11 | public HyteraBPEncryptionMethodForm(HyteraBPEncryptionRow row = null, bool batchMode = false)
12 | {
13 | InitializeComponent();
14 |
15 | optionsControl.OptionChanged += OptionsControl_OptionChanged;
16 |
17 | IsBatchMode = batchMode;
18 | if (IsBatchMode)
19 | {
20 | Text += " (Batch mode)";
21 | tbFrequency.Enabled = false;
22 | tbNotes.Enabled = false;
23 | }
24 |
25 | Utils.FillComboBoxData(cbKeyLength, typeof(HyteraKeyLengthEnum));
26 | cbKeyLength.SelectedIndex = 0;
27 |
28 | if (row == null)
29 | {
30 | EncryptionRow = new HyteraBPEncryptionRow();
31 | EncryptionRow.Key = new byte[HyteraBPEncryptionRow.KEY_SIZE];
32 | if (!IsBatchMode)
33 | tbFrequency.Text = Utils.GetFrequencyString(145500000);
34 | optionsControl.SetOptions(null);
35 | }
36 | else
37 | {
38 | EncryptionRow = row;
39 | if (!IsBatchMode)
40 | tbFrequency.Text = Utils.GetFrequencyString(row.Frequency);
41 | optionsControl.SetOptions(row.ActivateOptions);
42 |
43 | if (row.KeyLength == 40)
44 | Utils.SetComboBoxData(cbKeyLength, HyteraKeyLengthEnum.L40);
45 | else if (row.KeyLength == 128)
46 | Utils.SetComboBoxData(cbKeyLength, HyteraKeyLengthEnum.L128);
47 | else if (row.KeyLength == 256)
48 | Utils.SetComboBoxData(cbKeyLength, HyteraKeyLengthEnum.L256);
49 | else
50 | {
51 | nudKeyLength.Value = row.KeyLength;
52 | cbNonStandard.Checked = true;
53 | }
54 |
55 | if (Utils.IsArrayEmpty(row.Key))
56 | tbKey.Text = string.Empty;
57 | else
58 | tbKey.Text = Utils.BytesToHexString(row.Key).Substring(0, (int)(row.KeyLength / 4 + (row.KeyLength % 4 != 0 ? 1 : 0)));
59 |
60 | tbNotes.Text = row.Notes;
61 | }
62 |
63 | cbNonStandard_CheckedChanged(this, null);
64 | OptionsControl_OptionChanged(this, null);
65 | }
66 |
67 | private void OptionsControl_OptionChanged(object sender, EventArgs e)
68 | {
69 | tbFrequency.Enabled = optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.Frequency);
70 | cbKeyLength.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
71 | nudKeyLength.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
72 | cbNonStandard.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
73 | tbKey.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
74 | }
75 |
76 | private void btnOK_Click(object sender, EventArgs e)
77 | {
78 | string errorStr;
79 |
80 | if (optionsControl.IsExistErrors(out errorStr))
81 | {
82 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
83 | return;
84 | }
85 |
86 | uint freq = 0;
87 | if (!IsBatchMode && !Utils.ParseFrequency(tbFrequency.Text, out freq, out errorStr))
88 | {
89 | tbFrequency.Focus();
90 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
91 | return;
92 | }
93 |
94 | EncryptionRow.Frequency = freq;
95 | EncryptionRow.ActivateOptions = optionsControl.Options;
96 |
97 | byte[] key;
98 | try
99 | {
100 | key = Utils.HexStringToBytes(tbKey.Text);
101 | }
102 | catch
103 | {
104 | MessageBox.Show("Wrong Encryption Key Format.\r\nMust be HEX!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
105 | tbKey.Focus();
106 | return;
107 | }
108 |
109 | if (cbNonStandard.Checked)
110 | EncryptionRow.KeyLength = (uint)nudKeyLength.Value;
111 | else
112 | EncryptionRow.KeyLength = (uint)((HyteraKeyLengthEnum)(cbKeyLength.SelectedItem as DisplayTagObject).Tag);
113 | Buffer.BlockCopy(key, 0, EncryptionRow.Key, 0, key.Length > HyteraBPEncryptionRow.KEY_SIZE ? HyteraBPEncryptionRow.KEY_SIZE : key.Length);
114 |
115 | EncryptionRow.Notes = tbNotes.Text.Trim();
116 |
117 | DialogResult = DialogResult.OK;
118 | Close();
119 | }
120 |
121 | private void cbNonStandard_CheckedChanged(object sender, EventArgs e)
122 | {
123 | cbKeyLength.Visible = !cbNonStandard.Checked;
124 | nudKeyLength.Visible = cbNonStandard.Checked;
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/HyteraBPEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("Hytera BP")]
7 | [Serializable]
8 | public class HyteraBPEncryptionRow : DmrEncryptionRow
9 | {
10 | public const int KEY_SIZE = 32;
11 | public uint KeyLength { get; set; }
12 |
13 | public byte[] Key { get; set; }
14 |
15 | [JsonIgnore]
16 | public override string Description
17 | {
18 | get
19 | {
20 | if (ActivateOptions.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute))
21 | return $"Hytera BP: {ActivateOptions}";
22 | else
23 | return $"Hytera BP: KeyLen({(int)KeyLength}) {ActivateOptions}";
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/HyteraEPEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class HyteraEPEncryptionMethodForm : Form
7 | {
8 | public HyteraEPEncryptionRow EncryptionRow { get; private set; }
9 | public bool IsBatchMode { get; private set; }
10 |
11 | public HyteraEPEncryptionMethodForm(HyteraEPEncryptionRow row = null, bool batchMode = false)
12 | {
13 | InitializeComponent();
14 |
15 | optionsControl.OptionChanged += OptionsControl_OptionChanged;
16 |
17 | IsBatchMode = batchMode;
18 | if (IsBatchMode)
19 | {
20 | Text += " (Batch mode)";
21 | tbFrequency.Enabled = false;
22 | tbNotes.Enabled = false;
23 | }
24 |
25 | if (row == null)
26 | {
27 | EncryptionRow = new HyteraEPEncryptionRow();
28 | EncryptionRow.Key = new byte[HyteraEPEncryptionRow.KEY_SIZE];
29 | if (!IsBatchMode)
30 | tbFrequency.Text = Utils.GetFrequencyString(145500000);
31 | optionsControl.SetOptions(null);
32 | }
33 | else
34 | {
35 | EncryptionRow = row;
36 | if (!IsBatchMode)
37 | tbFrequency.Text = Utils.GetFrequencyString(row.Frequency);
38 | optionsControl.SetOptions(row.ActivateOptions);
39 |
40 | cbKeyID.Checked = row.ActivateOptions.IsActivated(DmrSelectedActivateOptionsEnum.KeyId);
41 | if (cbKeyID.Checked)
42 | tbKeyID.Text = row.ActivateOptions.KeyId.ToString();
43 |
44 | if (Utils.IsArrayEmpty(row.Key))
45 | tbKey.Text = string.Empty;
46 | else
47 | tbKey.Text = Utils.BytesToHexString(row.Key);
48 |
49 | tbNotes.Text = row.Notes;
50 | }
51 | cbKeyID_CheckedChanged(this, null);
52 | OptionsControl_OptionChanged(this, null);
53 | }
54 |
55 | private void OptionsControl_OptionChanged(object sender, EventArgs e)
56 | {
57 | tbFrequency.Enabled = optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.Frequency);
58 | tbKey.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
59 | }
60 |
61 | private void btnOK_Click(object sender, EventArgs e)
62 | {
63 | string errorStr;
64 |
65 | if (optionsControl.IsExistErrors(out errorStr))
66 | {
67 | if (!errorStr.Contains("no Frequency") || !cbKeyID.Checked)
68 | {
69 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
70 | return;
71 | }
72 | }
73 |
74 | uint freq = 0;
75 | if (!IsBatchMode && !Utils.ParseFrequency(tbFrequency.Text, out freq, out errorStr))
76 | {
77 | tbFrequency.Focus();
78 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
79 | return;
80 | }
81 |
82 | byte keyID = 0;
83 | if (cbKeyID.Checked)
84 | {
85 | try
86 | {
87 | keyID = byte.Parse(tbKeyID.Text);
88 | }
89 | catch
90 | {
91 | MessageBox.Show("Wrong KeyID", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
92 | tbKeyID.Focus();
93 | return;
94 | }
95 | }
96 |
97 | byte[] key;
98 | try
99 | {
100 | key = Utils.HexStringToBytes(tbKey.Text);
101 | }
102 | catch
103 | {
104 | MessageBox.Show("Wrong Encryption Key Format.\r\nMust be HEX!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
105 | tbKey.Focus();
106 | return;
107 | }
108 |
109 | Array.Clear(EncryptionRow.Key, 0, 5);
110 | if (key.Length > 0)
111 | Buffer.BlockCopy(key, 0, EncryptionRow.Key, 0, key.Length > MotorolaEPEncryptionRow.KEY_SIZE ? MotorolaEPEncryptionRow.KEY_SIZE : key.Length);
112 |
113 | EncryptionRow.Frequency = freq;
114 | EncryptionRow.ActivateOptions = optionsControl.Options;
115 | if (cbKeyID.Checked)
116 | {
117 | EncryptionRow.ActivateOptions.Activate(DmrSelectedActivateOptionsEnum.KeyId);
118 | EncryptionRow.ActivateOptions.KeyId = keyID;
119 | }
120 | else
121 | {
122 | EncryptionRow.ActivateOptions.Deactivate(DmrSelectedActivateOptionsEnum.KeyId);
123 | }
124 |
125 | EncryptionRow.Notes = tbNotes.Text.Trim();
126 |
127 | DialogResult = DialogResult.OK;
128 | Close();
129 | }
130 |
131 | private void cbKeyID_CheckedChanged(object sender, EventArgs e)
132 | {
133 | tbKeyID.Enabled = cbKeyID.Checked;
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/HyteraEPEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("Hytera EP")]
7 | [Serializable]
8 | public class HyteraEPEncryptionRow : DmrEncryptionRow
9 | {
10 | public const int KEY_SIZE = 5;
11 |
12 | public byte[] Key { get; set; }
13 |
14 | [JsonIgnore]
15 | public override string Description
16 | {
17 | get
18 | {
19 | if (ActivateOptions.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute))
20 | return $"Hytera EP: {ActivateOptions}";
21 | else
22 | return $"Hytera EP: Key({Utils.BytesToHexString(Key)}) {ActivateOptions}";
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/HyteraKeyLengthEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum HyteraKeyLengthEnum : ushort
4 | {
5 | [DisplayName("10 symbols (40 bits)")]
6 | L40 = 40,
7 | [DisplayName("32 symbols (128 bits)")]
8 | L128 = 128,
9 | [DisplayName("64 symbols (256 bits)")]
10 | L256 = 256
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/IActivateOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CFT
4 | {
5 | public interface IActivateOptions : IComparable
6 | {
7 | }
8 | }
--------------------------------------------------------------------------------
/src/IDmrEncryptionMethod.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public interface IDmrEncryptionMethod : IEncryptionMethod
4 | {
5 | }
6 | }
--------------------------------------------------------------------------------
/src/IEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public interface IEncryptionRow
4 | {
5 | uint Frequency { get; set; }
6 |
7 | string Notes { get; set; }
8 |
9 | ProtocolEnum Protocol { get; }
10 |
11 | string Description { get; }
12 |
13 | bool IsFrequencyNeed { get; }
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/ImportForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/ImportItem.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public class ImportItem
4 | {
5 | public uint Frequency { get; set; }
6 | public string Notes { get; set; }
7 | public IEncryptionRow EncryptionRow { get; set; }
8 | }
9 | }
--------------------------------------------------------------------------------
/src/KeyMapFunctionEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum KeyMapFunctionEnum
4 | {
5 | [Scanner(ScannerModelEnum.BCD436HP)]
6 | [Scanner(ScannerModelEnum.BCD536HP)]
7 | [Scanner(ScannerModelEnum.SDS100)]
8 | [Scanner(ScannerModelEnum.SDS200)]
9 | [Scanner(ScannerModelEnum.UBCD3600XLT)]
10 | [Scanner(ScannerModelEnum.SDS100E)]
11 | [Scanner(ScannerModelEnum.SDS200E)]
12 | [Scanner(ScannerModelEnum.UBCD436PT)]
13 | [Scanner(ScannerModelEnum.UBCD536PT)]
14 | [Scanner(ScannerModelEnum.USDS100)]
15 | [DisplayName("DEFAULT")]
16 | Default = 0,
17 | [Scanner(ScannerModelEnum.BCD436HP)]
18 | [Scanner(ScannerModelEnum.BCD536HP)]
19 | [Scanner(ScannerModelEnum.SDS100)]
20 | [Scanner(ScannerModelEnum.SDS200)]
21 | [DisplayName("Zip Code")]
22 | ZipCodeMenu = 1,
23 | [Scanner(ScannerModelEnum.BCD436HP)]
24 | [Scanner(ScannerModelEnum.BCD536HP)]
25 | [Scanner(ScannerModelEnum.SDS100)]
26 | [Scanner(ScannerModelEnum.SDS200)]
27 | [Scanner(ScannerModelEnum.UBCD3600XLT)]
28 | [Scanner(ScannerModelEnum.SDS100E)]
29 | [Scanner(ScannerModelEnum.SDS200E)]
30 | [DisplayName("Select Service")]
31 | SelectServiceMenu = 2,
32 | [Scanner(ScannerModelEnum.BCD436HP)]
33 | [Scanner(ScannerModelEnum.BCD536HP)]
34 | [Scanner(ScannerModelEnum.SDS100)]
35 | [Scanner(ScannerModelEnum.SDS200)]
36 | [Scanner(ScannerModelEnum.UBCD3600XLT)]
37 | [Scanner(ScannerModelEnum.SDS100E)]
38 | [Scanner(ScannerModelEnum.SDS200E)]
39 | [DisplayName("Search For ...")]
40 | SearchForMenu = 3,
41 | [Scanner(ScannerModelEnum.BCD436HP)]
42 | [Scanner(ScannerModelEnum.BCD536HP)]
43 | [Scanner(ScannerModelEnum.SDS100)]
44 | [Scanner(ScannerModelEnum.SDS200)]
45 | [Scanner(ScannerModelEnum.UBCD3600XLT)]
46 | [Scanner(ScannerModelEnum.SDS100E)]
47 | [Scanner(ScannerModelEnum.SDS200E)]
48 | [DisplayName("Select Lists to Monitor")]
49 | SelectListsToMonitorMenu = 4,
50 | [Scanner(ScannerModelEnum.BCD436HP)]
51 | [Scanner(ScannerModelEnum.BCD536HP)]
52 | [Scanner(ScannerModelEnum.UBCD3600XLT)]
53 | [DisplayName("RF Power Plot")]
54 | RFPowerPlotMenu = 5,
55 | [Scanner(ScannerModelEnum.BCD436HP)]
56 | [Scanner(ScannerModelEnum.BCD536HP)]
57 | [Scanner(ScannerModelEnum.SDS100)]
58 | [Scanner(ScannerModelEnum.SDS200)]
59 | [Scanner(ScannerModelEnum.UBCD3600XLT)]
60 | [Scanner(ScannerModelEnum.SDS100E)]
61 | [Scanner(ScannerModelEnum.SDS200E)]
62 | [DisplayName("Set Dimmer")]
63 | SetDimmerMenu = 6,
64 | [Scanner(ScannerModelEnum.BCD436HP)]
65 | [Scanner(ScannerModelEnum.BCD536HP)]
66 | [Scanner(ScannerModelEnum.SDS100)]
67 | [Scanner(ScannerModelEnum.SDS200)]
68 | [Scanner(ScannerModelEnum.UBCD3600XLT)]
69 | [Scanner(ScannerModelEnum.SDS100E)]
70 | [Scanner(ScannerModelEnum.SDS200E)]
71 | [DisplayName("Set CC Mode")]
72 | SetCCModeMenu = 7,
73 | [Scanner(ScannerModelEnum.SDS100)]
74 | [Scanner(ScannerModelEnum.SDS200)]
75 | [Scanner(ScannerModelEnum.SDS100E)]
76 | [Scanner(ScannerModelEnum.SDS200E)]
77 | [DisplayName("Waterfall")]
78 | WaterfallMenu = 8,
79 | [Scanner(ScannerModelEnum.SDS100)]
80 | [Scanner(ScannerModelEnum.SDS200)]
81 | [Scanner(ScannerModelEnum.SDS100E)]
82 | [Scanner(ScannerModelEnum.SDS200E)]
83 | [DisplayName("Filter")]
84 | FilterMenu = 9,
85 | [Scanner(ScannerModelEnum.BCD536HP)]
86 | [DisplayName("Range")]
87 | SelectRange = 10,
88 |
89 | [Scanner(ScannerModelEnum.BCD436HP)]
90 | [Scanner(ScannerModelEnum.BCD536HP)]
91 | [Scanner(ScannerModelEnum.SDS100)]
92 | [Scanner(ScannerModelEnum.SDS200)]
93 | [Scanner(ScannerModelEnum.UBCD3600XLT)]
94 | [Scanner(ScannerModelEnum.SDS100E)]
95 | [Scanner(ScannerModelEnum.SDS200E)]
96 | [Scanner(ScannerModelEnum.UBCD436PT)]
97 | [Scanner(ScannerModelEnum.UBCD536PT)]
98 | [Scanner(ScannerModelEnum.USDS100)]
99 | [DisplayName("Debug Logs")]
100 | DebugLogs = 11,
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/KeyMapping.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CFT
4 | {
5 | [Serializable]
6 | public class KeyMapping
7 | {
8 | public KeyMapFunctionEnum Key1 { get; set; } = KeyMapFunctionEnum.Default;
9 | public KeyMapFunctionEnum Key2 { get; set; } = KeyMapFunctionEnum.Default;
10 | public KeyMapFunctionEnum Key3 { get; set; } = KeyMapFunctionEnum.Default;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/KeyMappingForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class KeyMappingForm : Form
7 | {
8 | public KeyMapping KeyMapping { get; private set; }
9 |
10 | public KeyMappingForm(ScannerModelEnum model, KeyMapping keyMapping)
11 | {
12 | InitializeComponent();
13 |
14 | KeyMapping = keyMapping;
15 |
16 | switch(model)
17 | {
18 | case ScannerModelEnum.UBCD3600XLT:
19 | case ScannerModelEnum.BCD436HP:
20 | case ScannerModelEnum.UBCD436PT:
21 | lblKey1.Text = "ZIP";
22 | lblKey2.Text = "FUNC+ZIP";
23 | lblKey3.Visible = false;
24 | cbKey3Map.Visible = false;
25 | break;
26 | case ScannerModelEnum.BCD536HP:
27 | case ScannerModelEnum.UBCD536PT:
28 | lblKey1.Text = "ZIP";
29 | lblKey2.Text = "SERV";
30 | lblKey3.Text = "RANG";
31 | lblKey3.Visible = true;
32 | cbKey3Map.Visible = true;
33 | break;
34 | case ScannerModelEnum.SDS100:
35 | case ScannerModelEnum.SDS100E:
36 | case ScannerModelEnum.USDS100:
37 | lblKey1.Text = "ZIP";
38 | lblKey2.Text = "FUNC+ZIP";
39 | lblKey3.Visible = false;
40 | cbKey3Map.Visible = false;
41 | break;
42 | case ScannerModelEnum.SDS200:
43 | case ScannerModelEnum.SDS200E:
44 | lblKey1.Text = "ZIP";
45 | lblKey2.Text = "FUNC+ZIP";
46 | lblKey3.Visible = false;
47 | cbKey3Map.Visible = false;
48 | break;
49 | }
50 |
51 | FillComboBoxData(cbKey1Map, model);
52 | FillComboBoxData(cbKey2Map, model);
53 | FillComboBoxData(cbKey3Map, model);
54 |
55 | if (KeyMapping != null)
56 | {
57 | if (!Utils.SetComboBoxData(cbKey1Map, KeyMapping.Key1))
58 | Utils.SetComboBoxData(cbKey1Map, KeyMapFunctionEnum.Default);
59 | if (!Utils.SetComboBoxData(cbKey2Map, KeyMapping.Key2))
60 | Utils.SetComboBoxData(cbKey2Map, KeyMapFunctionEnum.Default);
61 | if (!Utils.SetComboBoxData(cbKey3Map, KeyMapping.Key3))
62 | Utils.SetComboBoxData(cbKey3Map, KeyMapFunctionEnum.Default);
63 | }
64 | else
65 | {
66 | Utils.SetComboBoxData(cbKey1Map, KeyMapFunctionEnum.Default);
67 | Utils.SetComboBoxData(cbKey2Map, KeyMapFunctionEnum.Default);
68 | Utils.SetComboBoxData(cbKey3Map, KeyMapFunctionEnum.Default);
69 | }
70 | }
71 |
72 | public void FillComboBoxData(ComboBox cb, ScannerModelEnum model)
73 | {
74 | cb.Items.Clear();
75 | foreach (KeyMapFunctionEnum item in Enum.GetValues(typeof(KeyMapFunctionEnum)))
76 | {
77 | var sa = Utils.GetAttributes(item);
78 | foreach (ScannerAttribute attr in sa)
79 | {
80 | if (attr.Model == model)
81 | {
82 | cb.Items.Add(new DisplayTagObject(item));
83 | break;
84 | }
85 | }
86 | }
87 | }
88 |
89 | private void btnOk_Click(object sender, EventArgs e)
90 | {
91 | if (KeyMapping == null)
92 | KeyMapping = new KeyMapping();
93 |
94 | KeyMapping.Key1 = (KeyMapFunctionEnum)Utils.GetComboBoxData(cbKey1Map.SelectedItem);
95 | KeyMapping.Key2 = (KeyMapFunctionEnum)Utils.GetComboBoxData(cbKey2Map.SelectedItem);
96 | KeyMapping.Key3 = (KeyMapFunctionEnum)Utils.GetComboBoxData(cbKey3Map.SelectedItem);
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/KeyMappingForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/KirisunBPEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class KirisunBPEncryptionMethodForm : Form
7 | {
8 | public KirisunBPEncryptionRow EncryptionRow { get; private set; }
9 | public bool IsBatchMode { get; private set; }
10 |
11 | public KirisunBPEncryptionMethodForm(KirisunBPEncryptionRow row = null, bool batchMode = false)
12 | {
13 | InitializeComponent();
14 |
15 | optionsControl.OptionChanged += OptionsControl_OptionChanged;
16 |
17 | IsBatchMode = batchMode;
18 | if (IsBatchMode)
19 | {
20 | Text += " (Batch mode)";
21 | tbFrequency.Enabled = false;
22 | tbNotes.Enabled = false;
23 | }
24 |
25 | Utils.FillComboBoxData(cbKeyLength, typeof(KirisunKeyLengthEnum));
26 | cbKeyLength.SelectedIndex = 0;
27 |
28 | if (row == null)
29 | {
30 | EncryptionRow = new KirisunBPEncryptionRow();
31 | EncryptionRow.Key = new byte[KirisunBPEncryptionRow.KEY_SIZE];
32 | if (!IsBatchMode)
33 | tbFrequency.Text = Utils.GetFrequencyString(145500000);
34 | optionsControl.SetOptions(null);
35 | }
36 | else
37 | {
38 | EncryptionRow = row;
39 | if (!IsBatchMode)
40 | tbFrequency.Text = Utils.GetFrequencyString(row.Frequency);
41 | optionsControl.SetOptions(row.ActivateOptions);
42 |
43 | if (row.KeyLength == 40)
44 | Utils.SetComboBoxData(cbKeyLength, KirisunKeyLengthEnum.L40);
45 | if (row.KeyLength == 64)
46 | Utils.SetComboBoxData(cbKeyLength, KirisunKeyLengthEnum.L64);
47 | else if (row.KeyLength == 128)
48 | Utils.SetComboBoxData(cbKeyLength, KirisunKeyLengthEnum.L128);
49 | else if (row.KeyLength == 192)
50 | Utils.SetComboBoxData(cbKeyLength, KirisunKeyLengthEnum.L192);
51 | else if (row.KeyLength == 256)
52 | Utils.SetComboBoxData(cbKeyLength, KirisunKeyLengthEnum.L256);
53 |
54 | if (Utils.IsArrayEmpty(row.Key))
55 | tbKey.Text = string.Empty;
56 | else
57 | tbKey.Text = Utils.BytesToHexString(row.Key).Substring(0, (int)(row.KeyLength / 4 + (row.KeyLength % 4 != 0 ? 1 : 0)));
58 |
59 | tbNotes.Text = row.Notes;
60 | }
61 |
62 | OptionsControl_OptionChanged(this, null);
63 | }
64 |
65 | private void OptionsControl_OptionChanged(object sender, EventArgs e)
66 | {
67 | tbFrequency.Enabled = optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.Frequency);
68 | cbKeyLength.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
69 | tbKey.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
70 | }
71 |
72 | private void btnOK_Click(object sender, EventArgs e)
73 | {
74 | string errorStr;
75 |
76 | if (optionsControl.IsExistErrors(out errorStr))
77 | {
78 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
79 | return;
80 | }
81 |
82 | uint freq = 0;
83 | if (!IsBatchMode && !Utils.ParseFrequency(tbFrequency.Text, out freq, out errorStr))
84 | {
85 | tbFrequency.Focus();
86 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
87 | return;
88 | }
89 |
90 | EncryptionRow.Frequency = freq;
91 | EncryptionRow.ActivateOptions = optionsControl.Options;
92 |
93 | byte[] key;
94 | try
95 | {
96 | key = Utils.HexStringToBytes(tbKey.Text);
97 | }
98 | catch
99 | {
100 | MessageBox.Show("Wrong Encryption Key Format.\r\nMust be HEX!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
101 | tbKey.Focus();
102 | return;
103 | }
104 |
105 | EncryptionRow.KeyLength = (uint)(KirisunKeyLengthEnum)(cbKeyLength.SelectedItem as DisplayTagObject).Tag;
106 | Buffer.BlockCopy(key, 0, EncryptionRow.Key, 0, key.Length > KirisunBPEncryptionRow.KEY_SIZE ? KirisunBPEncryptionRow.KEY_SIZE : key.Length);
107 |
108 | EncryptionRow.Notes = tbNotes.Text.Trim();
109 |
110 | DialogResult = DialogResult.OK;
111 | Close();
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/KirisunBPEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("Kirisun BP")]
7 | [Serializable]
8 | public class KirisunBPEncryptionRow : DmrEncryptionRow
9 | {
10 | public const int KEY_SIZE = 32;
11 | public uint KeyLength { get; set; }
12 |
13 | public byte[] Key { get; set; }
14 |
15 | [JsonIgnore]
16 | public override string Description
17 | {
18 | get
19 | {
20 | if (ActivateOptions.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute))
21 | return $"Kirisun BP: {ActivateOptions}";
22 | else
23 | return $"Kirisun BP: KeyLen({(int)KeyLength}) {ActivateOptions}";
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/KirisunKeyLengthEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum KirisunKeyLengthEnum : ushort
4 | {
5 | [DisplayName("10 symbols (40 bits)")]
6 | L40 = 40,
7 | [DisplayName("16 symbols (64 bits)")]
8 | L64 = 64,
9 | [DisplayName("32 symbols (128 bits)")]
10 | L128 = 128,
11 | [DisplayName("48 symbols (192 bits)")]
12 | L192 = 192,
13 | [DisplayName("64 symbols (256 bits)")]
14 | L256 = 256
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Licensing.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 |
5 | namespace CFT
6 | {
7 | [Serializable]
8 | public class Licensing
9 | {
10 | public const int UNLOCK_KEY_LEN = 32;
11 |
12 | public byte[] HyteraBPUnlockKey { get; set; }
13 |
14 | public byte[] MotorolaBPUnlockKey { get; set; }
15 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
16 | public byte[] MotorolaEPUnlockKey { get; set; } = new byte[UNLOCK_KEY_LEN];
17 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
18 | public byte[] NxdnScramblerUnlockKey { get; set; } = new byte[UNLOCK_KEY_LEN];
19 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
20 | public byte[] P25ADPUnlockKey { get; set; } = new byte[UNLOCK_KEY_LEN];
21 | public byte[] P25DESUnlockKey { get; set; } = new byte[UNLOCK_KEY_LEN];
22 | public byte[] DMRAESUnlockKey { get; set; } = new byte[UNLOCK_KEY_LEN];
23 | public byte[] HyteraEPUnlockKey { get; set; } = new byte[UNLOCK_KEY_LEN];
24 | public byte[] P25AESUnlockKey { get; set; } = new byte[UNLOCK_KEY_LEN];
25 |
26 | public bool IsKeysExist
27 | {
28 | get
29 | {
30 | return !Utils.IsArrayEmpty(MotorolaBPUnlockKey) ||
31 | !Utils.IsArrayEmpty(HyteraBPUnlockKey) ||
32 | !Utils.IsArrayEmpty(HyteraEPUnlockKey) ||
33 | !Utils.IsArrayEmpty(MotorolaEPUnlockKey) ||
34 | !Utils.IsArrayEmpty(P25ADPUnlockKey) ||
35 | !Utils.IsArrayEmpty(P25DESUnlockKey) ||
36 | !Utils.IsArrayEmpty(DMRAESUnlockKey) ||
37 | !Utils.IsArrayEmpty(NxdnScramblerUnlockKey) ||
38 | !Utils.IsArrayEmpty(P25AESUnlockKey);
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/LicensingForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/ListViewExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Runtime.InteropServices;
4 | using System.Windows.Forms;
5 |
6 | namespace CFT
7 | {
8 | [EditorBrowsable(EditorBrowsableState.Never)]
9 | public static class ListViewExtensions
10 | {
11 | [StructLayout(LayoutKind.Sequential)]
12 | public struct HDITEM
13 | {
14 | public Mask mask;
15 | public int cxy;
16 | [MarshalAs(UnmanagedType.LPTStr)] public string pszText;
17 | public IntPtr hbm;
18 | public int cchTextMax;
19 | public Format fmt;
20 | public IntPtr lParam;
21 | // _WIN32_IE >= 0x0300
22 | public int iImage;
23 | public int iOrder;
24 | // _WIN32_IE >= 0x0500
25 | public uint type;
26 | public IntPtr pvFilter;
27 | // _WIN32_WINNT >= 0x0600
28 | public uint state;
29 |
30 | [Flags]
31 | public enum Mask
32 | {
33 | Format = 0x4, // HDI_FORMAT
34 | };
35 |
36 | [Flags]
37 | public enum Format
38 | {
39 | SortDown = 0x200, // HDF_SORTDOWN
40 | SortUp = 0x400, // HDF_SORTUP
41 | };
42 | };
43 |
44 | public const int LVM_FIRST = 0x1000;
45 | public const int LVM_GETHEADER = LVM_FIRST + 31;
46 |
47 | public const int HDM_FIRST = 0x1200;
48 | public const int HDM_GETITEM = HDM_FIRST + 11;
49 | public const int HDM_SETITEM = HDM_FIRST + 12;
50 |
51 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
52 | public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
53 |
54 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
55 | public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, ref HDITEM lParam);
56 |
57 | public static void SetSortIcon(ListView listViewControl, int columnIndex, SortOrder order)
58 | {
59 | IntPtr columnHeader = SendMessage(listViewControl.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
60 | for (int columnNumber = 0; columnNumber <= listViewControl.Columns.Count - 1; columnNumber++)
61 | {
62 | var columnPtr = new IntPtr(columnNumber);
63 | var item = new HDITEM
64 | {
65 | mask = HDITEM.Mask.Format
66 | };
67 |
68 | if (SendMessage(columnHeader, HDM_GETITEM, columnPtr, ref item) == IntPtr.Zero)
69 | {
70 | throw new Win32Exception();
71 | }
72 |
73 | if (order != SortOrder.None && columnNumber == columnIndex)
74 | {
75 | switch (order)
76 | {
77 | case SortOrder.Ascending:
78 | item.fmt &= ~HDITEM.Format.SortDown;
79 | item.fmt |= HDITEM.Format.SortUp;
80 | break;
81 | case SortOrder.Descending:
82 | item.fmt &= ~HDITEM.Format.SortUp;
83 | item.fmt |= HDITEM.Format.SortDown;
84 | break;
85 | }
86 | }
87 | else
88 | {
89 | item.fmt &= ~HDITEM.Format.SortDown & ~HDITEM.Format.SortUp;
90 | }
91 |
92 | if (SendMessage(columnHeader, HDM_SETITEM, columnPtr, ref item) == IntPtr.Zero)
93 | {
94 | throw new Win32Exception();
95 | }
96 | }
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/MacAddressForm.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Forms;
2 |
3 | namespace CFT
4 | {
5 | public partial class MacAddressForm : Form
6 | {
7 | public byte [] MacAddress { get; set; }
8 |
9 | public MacAddressForm(byte[] macAddress)
10 | {
11 | InitializeComponent();
12 |
13 | MacAddress = macAddress;
14 |
15 | if(macAddress == null || macAddress.Length != 6)
16 | btnOk.Enabled = false;
17 | else
18 | {
19 | tbMAC3.Text = macAddress[3].ToString("X2");
20 | tbMAC4.Text = macAddress[4].ToString("X2");
21 | tbMAC5.Text = macAddress[5].ToString("X2");
22 | }
23 | }
24 |
25 | private void btnOk_Click(object sender, System.EventArgs e)
26 | {
27 | MacAddress[0] = byte.Parse(tbMAC0.Text, System.Globalization.NumberStyles.HexNumber);
28 | MacAddress[1] = byte.Parse(tbMAC1.Text, System.Globalization.NumberStyles.HexNumber);
29 | MacAddress[2] = byte.Parse(tbMAC2.Text, System.Globalization.NumberStyles.HexNumber);
30 |
31 | try
32 | {
33 | MacAddress[3] = byte.Parse(tbMAC3.Text, System.Globalization.NumberStyles.HexNumber);
34 | }
35 | catch
36 | {
37 | MessageBox.Show("Wrong MAC Address [3]");
38 | tbMAC3.Focus();
39 | return;
40 | }
41 | try
42 | {
43 | MacAddress[4] = byte.Parse(tbMAC4.Text, System.Globalization.NumberStyles.HexNumber);
44 | }
45 | catch
46 | {
47 | MessageBox.Show("Wrong MAC Address [4]");
48 | tbMAC4.Focus();
49 | return;
50 | }
51 | try
52 | {
53 | MacAddress[5] = byte.Parse(tbMAC5.Text, System.Globalization.NumberStyles.HexNumber);
54 | }
55 | catch
56 | {
57 | MessageBox.Show("Wrong MAC Address [5]");
58 | tbMAC5.Focus();
59 | return;
60 | }
61 |
62 | DialogResult = DialogResult.OK;
63 | Close();
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/MacAddressForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/MotorolaBPEncryptionMethod.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public class MotorolaBPEncryptionMethod : IEncryptionMethod
4 | {
5 | public string Name => "Motorola BP";
6 | public byte Key { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/MotorolaBPEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class MotorolaBPEncryptionMethodForm : Form
7 | {
8 | public MotorolaBPEncryptionRow EncryptionRow { get; private set; }
9 |
10 | public bool IsBatchMode { get; private set; }
11 |
12 | public MotorolaBPEncryptionMethodForm(MotorolaBPEncryptionRow row = null, bool batchMode = false)
13 | {
14 | InitializeComponent();
15 |
16 | optionsControl.OptionChanged += OptionsControl_OptionChanged;
17 |
18 | IsBatchMode = batchMode;
19 | if (IsBatchMode)
20 | {
21 | Text += " (Batch mode)";
22 | tbFrequency.Enabled = false;
23 | tbNotes.Enabled = false;
24 | }
25 |
26 | if (row == null)
27 | {
28 | EncryptionRow = new MotorolaBPEncryptionRow();
29 | if (!IsBatchMode)
30 | tbFrequency.Text = Utils.GetFrequencyString(145500000);
31 | optionsControl.SetOptions(null);
32 | }
33 | else
34 | {
35 | EncryptionRow = row;
36 | if (!IsBatchMode)
37 | tbFrequency.Text = Utils.GetFrequencyString(row.Frequency);
38 | optionsControl.SetOptions(row.ActivateOptions);
39 | nudKey.Value = row.Key;
40 | tbNotes.Text = row.Notes;
41 | }
42 | OptionsControl_OptionChanged(this, null);
43 | }
44 |
45 | private void OptionsControl_OptionChanged(object sender, EventArgs e)
46 | {
47 | tbFrequency.Enabled = optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.Frequency);
48 | nudKey.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
49 | }
50 |
51 | private void btnOK_Click(object sender, EventArgs e)
52 | {
53 | string errorStr;
54 |
55 | if (optionsControl.IsExistErrors(out errorStr))
56 | {
57 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
58 | return;
59 | }
60 |
61 | uint freq = 0;
62 | if (!IsBatchMode && !Utils.ParseFrequency(tbFrequency.Text, out freq, out errorStr))
63 | {
64 | tbFrequency.Focus();
65 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
66 | return;
67 | }
68 |
69 | EncryptionRow.Frequency = freq;
70 | EncryptionRow.ActivateOptions = optionsControl.Options;
71 | EncryptionRow.Key = (byte)nudKey.Value;
72 | EncryptionRow.Notes = tbNotes.Text.Trim();
73 |
74 | DialogResult = DialogResult.OK;
75 | Close();
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/MotorolaBPEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("Motorola BP")]
7 |
8 | [Serializable]
9 | public class MotorolaBPEncryptionRow : DmrEncryptionRow
10 | {
11 | public byte Key { get; set; }
12 |
13 | public MotorolaBPEncryptionRow()
14 | {
15 | Key = 1;
16 | ActivateOptions = new DmrActivateOptions();
17 | }
18 |
19 | [JsonIgnore]
20 | public override string Description
21 | {
22 | get
23 | {
24 | if (ActivateOptions.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute))
25 | return $"Motorola BP: {ActivateOptions}";
26 | else
27 | return $"Motorola BP: Key({Key}) {ActivateOptions}";
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/MotorolaEPEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class MotorolaEPEncryptionMethodForm : Form
7 | {
8 | public MotorolaEPEncryptionRow EncryptionRow { get; private set; }
9 | public bool IsBatchMode { get; private set; }
10 |
11 | public MotorolaEPEncryptionMethodForm(MotorolaEPEncryptionRow row = null, bool batchMode = false)
12 | {
13 | InitializeComponent();
14 |
15 | optionsControl.OptionChanged += OptionsControl_OptionChanged;
16 |
17 | IsBatchMode = batchMode;
18 | if (IsBatchMode)
19 | {
20 | Text += " (Batch mode)";
21 | tbFrequency.Enabled = false;
22 | tbNotes.Enabled = false;
23 | }
24 |
25 | if (row == null)
26 | {
27 | EncryptionRow = new MotorolaEPEncryptionRow();
28 | EncryptionRow.Key = new byte[MotorolaEPEncryptionRow.KEY_SIZE];
29 | if (!IsBatchMode)
30 | tbFrequency.Text = Utils.GetFrequencyString(145500000);
31 | optionsControl.SetOptions(null);
32 | }
33 | else
34 | {
35 | EncryptionRow = row;
36 | if (!IsBatchMode)
37 | tbFrequency.Text = Utils.GetFrequencyString(row.Frequency);
38 | optionsControl.SetOptions(row.ActivateOptions);
39 |
40 | cbKeyID.Checked = row.ActivateOptions.IsActivated(DmrSelectedActivateOptionsEnum.KeyId);
41 | if (cbKeyID.Checked)
42 | tbKeyID.Text = row.ActivateOptions.KeyId.ToString();
43 |
44 | if (Utils.IsArrayEmpty(row.Key))
45 | tbKey.Text = string.Empty;
46 | else
47 | tbKey.Text = Utils.BytesToHexString(row.Key);
48 |
49 | tbNotes.Text = row.Notes;
50 | }
51 | cbKeyID_CheckedChanged(this, null);
52 | OptionsControl_OptionChanged(this, null);
53 | }
54 |
55 | private void OptionsControl_OptionChanged(object sender, EventArgs e)
56 | {
57 | tbFrequency.Enabled = optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.Frequency);
58 | tbKey.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
59 | }
60 |
61 | private void btnOK_Click(object sender, EventArgs e)
62 | {
63 | string errorStr;
64 |
65 | if (optionsControl.IsExistErrors(out errorStr))
66 | {
67 | if (!errorStr.Contains("no Frequency") || !cbKeyID.Checked)
68 | {
69 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
70 | return;
71 | }
72 | }
73 |
74 | uint freq = 0;
75 | if (!IsBatchMode && !Utils.ParseFrequency(tbFrequency.Text, out freq, out errorStr))
76 | {
77 | tbFrequency.Focus();
78 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
79 | return;
80 | }
81 |
82 | byte keyID = 0;
83 | if (cbKeyID.Checked)
84 | {
85 | try
86 | {
87 | keyID = byte.Parse(tbKeyID.Text);
88 | }
89 | catch
90 | {
91 | MessageBox.Show("Wrong KeyID", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
92 | tbKeyID.Focus();
93 | return;
94 | }
95 | }
96 |
97 | byte[] key;
98 | try
99 | {
100 | key = Utils.HexStringToBytes(tbKey.Text);
101 | }
102 | catch
103 | {
104 | MessageBox.Show("Wrong Encryption Key Format.\r\nMust be HEX!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
105 | tbKey.Focus();
106 | return;
107 | }
108 |
109 | Array.Clear(EncryptionRow.Key, 0, 5);
110 | if (key.Length > 0)
111 | Buffer.BlockCopy(key, 0, EncryptionRow.Key, 0, key.Length > MotorolaEPEncryptionRow.KEY_SIZE ? MotorolaEPEncryptionRow.KEY_SIZE : key.Length);
112 |
113 | EncryptionRow.Frequency = freq;
114 | EncryptionRow.ActivateOptions = optionsControl.Options;
115 | if (cbKeyID.Checked)
116 | {
117 | EncryptionRow.ActivateOptions.Activate(DmrSelectedActivateOptionsEnum.KeyId);
118 | EncryptionRow.ActivateOptions.KeyId = keyID;
119 | }
120 | else
121 | {
122 | EncryptionRow.ActivateOptions.Deactivate(DmrSelectedActivateOptionsEnum.KeyId);
123 | }
124 |
125 | EncryptionRow.Notes = tbNotes.Text.Trim();
126 |
127 | DialogResult = DialogResult.OK;
128 | Close();
129 | }
130 |
131 | private void cbKeyID_CheckedChanged(object sender, EventArgs e)
132 | {
133 | tbKeyID.Enabled = cbKeyID.Checked;
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/MotorolaEPEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("Motorola EP")]
7 | [Serializable]
8 | public class MotorolaEPEncryptionRow : DmrEncryptionRow
9 | {
10 | public const int KEY_SIZE = 5;
11 |
12 | public byte[] Key { get; set; }
13 |
14 | [JsonIgnore]
15 | public override string Description
16 | {
17 | get
18 | {
19 | if (ActivateOptions.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute))
20 | return $"Motorola EP: {ActivateOptions}";
21 | else
22 | return $"Motorola EP: Key({Utils.BytesToHexString(Key)}) {ActivateOptions}";
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/NxdnActivateOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace CFT
5 | {
6 | [Serializable]
7 | public class NxdnActivateOptions : IActivateOptions
8 | {
9 | public NxdnSelectedActivateOptionsEnum Options { get; set; }
10 | public byte RAN { get; set; }
11 | public ushort GroupID { get; set; }
12 | public byte KeyID { get; set; }
13 | public ushort SourceID { get; set; }
14 |
15 | public NxdnActivateOptions()
16 | {
17 | Options = NxdnSelectedActivateOptionsEnum.Frequency;
18 | }
19 |
20 | public bool IsActivated(NxdnSelectedActivateOptionsEnum option)
21 | {
22 | return (Options & option) == option;
23 | }
24 |
25 | public void Activate(NxdnSelectedActivateOptionsEnum option)
26 | {
27 | Options = option | option;
28 | }
29 |
30 | public override string ToString()
31 | {
32 | var sb = new StringBuilder();
33 | if (IsActivated(NxdnSelectedActivateOptionsEnum.RAN))
34 | sb.Append($"RAN({RAN}) ");
35 | if (IsActivated(NxdnSelectedActivateOptionsEnum.GroupID))
36 | sb.Append($"GroupID({GroupID}) ");
37 | if (IsActivated(NxdnSelectedActivateOptionsEnum.KeyID))
38 | sb.Append($"KeyID({KeyID}) ");
39 | if (IsActivated(NxdnSelectedActivateOptionsEnum.SourceID))
40 | sb.Append($"SourceID({SourceID}) ");
41 | if (IsActivated(NxdnSelectedActivateOptionsEnum.ForceMute))
42 | sb.Append($"Force Mute");
43 | return sb.ToString();
44 | }
45 |
46 | public int CompareTo(object obj)
47 | {
48 | var o = obj as NxdnActivateOptions;
49 | if (o == null)
50 | return 1;
51 |
52 | if (o.Options != Options)
53 | return 1;
54 |
55 | if (IsActivated(NxdnSelectedActivateOptionsEnum.RAN) &&
56 | o.RAN != RAN)
57 | return 1;
58 |
59 | if (IsActivated(NxdnSelectedActivateOptionsEnum.GroupID) &&
60 | o.GroupID != GroupID)
61 | return 1;
62 |
63 | if (IsActivated(NxdnSelectedActivateOptionsEnum.KeyID) &&
64 | o.KeyID != KeyID)
65 | return 1;
66 |
67 | if (IsActivated(NxdnSelectedActivateOptionsEnum.SourceID) &&
68 | o.SourceID != SourceID)
69 | return 1;
70 |
71 | return 0;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/NxdnCypherTypeEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum NxdnCypherTypeEnum
4 | {
5 | None = 0,
6 | Scrambler = 1,
7 | Aes = 2,
8 | Des = 3
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/NxdnScramblerEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("NXDN Scrambler")]
7 | [Serializable]
8 | public class NxdnScramblerEncryptionRow : BaseEncryptionRow
9 | {
10 | public ushort Key { get; set; }
11 |
12 | public NxdnActivateOptions ActivateOptions { get; set; }
13 |
14 | [JsonIgnore]
15 | public override ProtocolEnum Protocol => ProtocolEnum.NXDN;
16 |
17 | [JsonIgnore]
18 | public override string Description
19 | {
20 | get
21 | {
22 | if (ActivateOptions.IsActivated(NxdnSelectedActivateOptionsEnum.ForceMute))
23 | return $"NXDN Scrambler: {ActivateOptions}";
24 | else
25 | return $"NXDN Scrambler: Key({Key}) {ActivateOptions}";
26 | }
27 | }
28 |
29 | public override bool IsFrequencyNeed => ActivateOptions == null ? true : ActivateOptions.IsActivated(NxdnSelectedActivateOptionsEnum.Frequency);
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/NxdnSelectOptionsEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | [System.Flags]
4 | public enum NxdnSelectOptionsEnum : uint
5 | {
6 | RAN = 1 << 0,
7 | GID = 1 << 1,
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/NxdnSelectedActivateOptionsEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | [System.Flags]
4 | public enum NxdnSelectedActivateOptionsEnum : uint
5 | {
6 | RAN = 1 << 0,
7 | GroupID = 1 << 1,
8 | Frequency = 1 << 2,
9 | KeyID = 1 << 3,
10 | SourceID = 1 << 4,
11 |
12 | ForceMute = 1 << 15
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/P25ADPEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class P25ADPEncryptionMethodForm : Form
7 | {
8 | public P25ADPEncryptionRow EncryptionRow { get; private set; }
9 | public bool IsBatchMode { get; private set; }
10 |
11 | public P25ADPEncryptionMethodForm(P25ADPEncryptionRow row = null, bool batchMode = false)
12 | {
13 | InitializeComponent();
14 |
15 | optionsControl.OptionChanged += OptionsControl_OptionChanged;
16 |
17 | IsBatchMode = batchMode;
18 | if (IsBatchMode)
19 | {
20 | Text += " (Batch mode)";
21 | tbFrequency.Enabled = false;
22 | tbNotes.Enabled = false;
23 | }
24 |
25 | if (row == null)
26 | {
27 | EncryptionRow = new P25ADPEncryptionRow();
28 | EncryptionRow.Key = new byte[P25ADPEncryptionRow.KEY_SIZE];
29 | if (!IsBatchMode)
30 | tbFrequency.Text = Utils.GetFrequencyString(145500000);
31 | optionsControl.SetOptions(null);
32 | }
33 | else
34 | {
35 | EncryptionRow = row;
36 | if (!IsBatchMode)
37 | tbFrequency.Text = Utils.GetFrequencyString(row.Frequency);
38 | optionsControl.SetOptions(row.ActivateOptions);
39 |
40 | if (Utils.IsArrayEmpty(row.Key))
41 | tbKey.Text = string.Empty;
42 | else
43 | tbKey.Text = Utils.BytesToHexString(row.Key);
44 |
45 | tbNotes.Text = row.Notes;
46 | }
47 | OptionsControl_OptionChanged(this, null);
48 | }
49 |
50 | private void OptionsControl_OptionChanged(object sender, EventArgs e)
51 | {
52 | tbFrequency.Enabled = optionsControl.Options.IsActivated(P25SelectedActivateOptionsEnum.Frequency);
53 | tbKey.Enabled = !optionsControl.Options.IsActivated(P25SelectedActivateOptionsEnum.ForceMute);
54 | }
55 |
56 | private void btnOK_Click(object sender, EventArgs e)
57 | {
58 | string errorStr;
59 |
60 | if (optionsControl.IsExistErrors(out errorStr))
61 | {
62 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
63 | return;
64 | }
65 |
66 | uint freq = 0;
67 | if (!IsBatchMode && !Utils.ParseFrequency(tbFrequency.Text, out freq, out errorStr))
68 | {
69 | tbFrequency.Focus();
70 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
71 | return;
72 | }
73 |
74 | byte[] key;
75 | try
76 | {
77 | key = Utils.HexStringToBytes(tbKey.Text);
78 | }
79 | catch
80 | {
81 | MessageBox.Show("Wrong Encryption Key Format.\r\nMust be HEX!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
82 | tbKey.Focus();
83 | return;
84 | }
85 |
86 | Array.Clear(EncryptionRow.Key, 0, 5);
87 | if (key.Length > 0)
88 | Buffer.BlockCopy(key, 0, EncryptionRow.Key, 0, key.Length > P25ADPEncryptionRow.KEY_SIZE ? P25ADPEncryptionRow.KEY_SIZE : key.Length);
89 |
90 | EncryptionRow.Frequency = freq;
91 | EncryptionRow.ActivateOptions = optionsControl.Options;
92 |
93 | EncryptionRow.Notes = tbNotes.Text.Trim();
94 |
95 | DialogResult = DialogResult.OK;
96 | Close();
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/P25ADPEncryptionMethodForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/P25ADPEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("P25 ADP")]
7 | [Serializable]
8 | public class P25ADPEncryptionRow : P25EncryptionRow
9 | {
10 | public const int KEY_SIZE = 5;
11 |
12 | public byte[] Key { get; set; }
13 |
14 | [JsonIgnore]
15 | public override string Description
16 | {
17 | get
18 | {
19 | if (!string.IsNullOrEmpty($"{ActivateOptions}"))
20 | return $"P25 ADP: {ActivateOptions}";
21 | else
22 | return $"P25 ADP";
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/P25AESEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class P25AESEncryptionMethodForm : Form
7 | {
8 | public P25AESEncryptionRow EncryptionRow { get; private set; }
9 | public bool IsBatchMode { get; private set; }
10 |
11 | public P25AESEncryptionMethodForm(P25AESEncryptionRow row = null, bool batchMode = false)
12 | {
13 | InitializeComponent();
14 |
15 | optionsControl.OptionChanged += OptionsControl_OptionChanged;
16 |
17 | IsBatchMode = batchMode;
18 | if (IsBatchMode)
19 | {
20 | Text += " (Batch mode)";
21 | tbFrequency.Enabled = false;
22 | tbNotes.Enabled = false;
23 | }
24 |
25 | if (row == null)
26 | {
27 | EncryptionRow = new P25AESEncryptionRow();
28 | EncryptionRow.Key = new byte[P25AESEncryptionRow.KEY_SIZE];
29 | if (!IsBatchMode)
30 | tbFrequency.Text = Utils.GetFrequencyString(145500000);
31 | optionsControl.SetOptions(null);
32 | }
33 | else
34 | {
35 | EncryptionRow = row;
36 | if (!IsBatchMode)
37 | tbFrequency.Text = Utils.GetFrequencyString(row.Frequency);
38 | optionsControl.SetOptions(row.ActivateOptions);
39 |
40 | if (Utils.IsArrayEmpty(row.Key))
41 | tbKey.Text = string.Empty;
42 | else
43 | tbKey.Text = Utils.BytesToHexString(row.Key);
44 |
45 | tbNotes.Text = row.Notes;
46 | }
47 | OptionsControl_OptionChanged(this, null);
48 | }
49 |
50 | private void OptionsControl_OptionChanged(object sender, EventArgs e)
51 | {
52 | tbFrequency.Enabled = optionsControl.Options.IsActivated(P25SelectedActivateOptionsEnum.Frequency);
53 | tbKey.Enabled = !optionsControl.Options.IsActivated(P25SelectedActivateOptionsEnum.ForceMute);
54 | }
55 |
56 | private void btnOK_Click(object sender, EventArgs e)
57 | {
58 | string errorStr;
59 |
60 | if (optionsControl.IsExistErrors(out errorStr))
61 | {
62 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
63 | return;
64 | }
65 |
66 | uint freq = 0;
67 | if (!IsBatchMode && !Utils.ParseFrequency(tbFrequency.Text, out freq, out errorStr))
68 | {
69 | tbFrequency.Focus();
70 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
71 | return;
72 | }
73 |
74 | byte[] key;
75 | try
76 | {
77 | key = Utils.HexStringToBytes(tbKey.Text);
78 | }
79 | catch
80 | {
81 | MessageBox.Show("Wrong Encryption Key Format.\r\nMust be HEX!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
82 | tbKey.Focus();
83 | return;
84 | }
85 |
86 | Array.Clear(EncryptionRow.Key, 0, 5);
87 | if (key.Length > 0)
88 | Buffer.BlockCopy(key, 0, EncryptionRow.Key, 0, key.Length > P25AESEncryptionRow.KEY_SIZE ? P25AESEncryptionRow.KEY_SIZE : key.Length);
89 |
90 | EncryptionRow.Frequency = freq;
91 | EncryptionRow.ActivateOptions = optionsControl.Options;
92 |
93 | EncryptionRow.Notes = tbNotes.Text.Trim();
94 |
95 | DialogResult = DialogResult.OK;
96 | Close();
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/P25AESEncryptionMethodForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/P25AESEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("P25 AES")]
7 | [Serializable]
8 | public class P25AESEncryptionRow : P25EncryptionRow
9 | {
10 | public const int KEY_SIZE = 32;
11 |
12 | public byte[] Key { get; set; }
13 |
14 | [JsonIgnore]
15 | public override string Description
16 | {
17 | get
18 | {
19 | if (!string.IsNullOrEmpty($"{ActivateOptions}"))
20 | return $"P25 AES: {ActivateOptions}";
21 | else
22 | return $"P25 AES";
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/P25ActivateOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace CFT
5 | {
6 | [Serializable]
7 | public class P25ActivateOptions : IActivateOptions
8 | {
9 | public P25SelectedActivateOptionsEnum Options { get; set; }
10 | public ushort NAC { get; set; }
11 | public uint GroupID { get; set; }
12 | public ushort KeyID { get; set; }
13 | public uint SourceID { get; set; }
14 |
15 | public P25ActivateOptions()
16 | {
17 | Options = P25SelectedActivateOptionsEnum.Frequency;
18 | }
19 |
20 | public bool IsActivated(P25SelectedActivateOptionsEnum option)
21 | {
22 | return (Options & option) == option;
23 | }
24 |
25 | public void Activate(P25SelectedActivateOptionsEnum option)
26 | {
27 | Options = option | option;
28 | }
29 |
30 | public override string ToString()
31 | {
32 | var sb = new StringBuilder();
33 | if (IsActivated(P25SelectedActivateOptionsEnum.NAC))
34 | sb.Append($"NAC({NAC:X}) ");
35 | if (IsActivated(P25SelectedActivateOptionsEnum.GroupID))
36 | sb.Append($"GroupID({GroupID}) ");
37 | if (IsActivated(P25SelectedActivateOptionsEnum.KeyID))
38 | sb.Append($"KeyID({KeyID:X}) ");
39 | if (IsActivated(P25SelectedActivateOptionsEnum.SourceID))
40 | sb.Append($"SourceID({SourceID}) ");
41 | if (IsActivated(P25SelectedActivateOptionsEnum.ForceMute))
42 | sb.Append($"Force Mute");
43 | return sb.ToString();
44 | }
45 |
46 | public int CompareTo(object obj)
47 | {
48 | var o = obj as P25ActivateOptions;
49 | if (o == null)
50 | return 1;
51 |
52 | if (o.Options != Options)
53 | return 1;
54 |
55 | if (IsActivated(P25SelectedActivateOptionsEnum.NAC) &&
56 | o.NAC != NAC)
57 | return 1;
58 |
59 | if (IsActivated(P25SelectedActivateOptionsEnum.GroupID) &&
60 | o.GroupID != GroupID)
61 | return 1;
62 |
63 | if (IsActivated(P25SelectedActivateOptionsEnum.KeyID) &&
64 | o.KeyID != KeyID)
65 | return 1;
66 |
67 | if (IsActivated(P25SelectedActivateOptionsEnum.SourceID) &&
68 | o.SourceID != SourceID)
69 | return 1;
70 |
71 | return 0;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/P25DESEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class P25DESEncryptionMethodForm : Form
7 | {
8 | public P25DESEncryptionRow EncryptionRow { get; private set; }
9 | public bool IsBatchMode { get; private set; }
10 |
11 | public P25DESEncryptionMethodForm(P25DESEncryptionRow row = null, bool batchMode = false)
12 | {
13 | InitializeComponent();
14 |
15 | optionsControl.OptionChanged += OptionsControl_OptionChanged;
16 |
17 | IsBatchMode = batchMode;
18 | if (IsBatchMode)
19 | {
20 | Text += " (Batch mode)";
21 | tbFrequency.Enabled = false;
22 | tbNotes.Enabled = false;
23 | }
24 |
25 | if (row == null)
26 | {
27 | EncryptionRow = new P25DESEncryptionRow();
28 | EncryptionRow.Key = new byte[P25DESEncryptionRow.KEY_SIZE];
29 | if (!IsBatchMode)
30 | tbFrequency.Text = Utils.GetFrequencyString(145500000);
31 | optionsControl.SetOptions(null);
32 | }
33 | else
34 | {
35 | EncryptionRow = row;
36 | if (!IsBatchMode)
37 | tbFrequency.Text = Utils.GetFrequencyString(row.Frequency);
38 | optionsControl.SetOptions(row.ActivateOptions);
39 |
40 | if (Utils.IsArrayEmpty(row.Key))
41 | tbKey.Text = string.Empty;
42 | else
43 | tbKey.Text = Utils.BytesToHexString(row.Key);
44 |
45 | tbNotes.Text = row.Notes;
46 | }
47 | OptionsControl_OptionChanged(this, null);
48 | }
49 |
50 | private void OptionsControl_OptionChanged(object sender, EventArgs e)
51 | {
52 | tbFrequency.Enabled = optionsControl.Options.IsActivated(P25SelectedActivateOptionsEnum.Frequency);
53 | tbKey.Enabled = !optionsControl.Options.IsActivated(P25SelectedActivateOptionsEnum.ForceMute);
54 | }
55 |
56 | private void btnOK_Click(object sender, EventArgs e)
57 | {
58 | string errorStr;
59 |
60 | if (optionsControl.IsExistErrors(out errorStr))
61 | {
62 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
63 | return;
64 | }
65 |
66 | uint freq = 0;
67 | if (!IsBatchMode && !Utils.ParseFrequency(tbFrequency.Text, out freq, out errorStr))
68 | {
69 | tbFrequency.Focus();
70 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
71 | return;
72 | }
73 |
74 | byte[] key;
75 | try
76 | {
77 | key = Utils.HexStringToBytes(tbKey.Text);
78 | }
79 | catch
80 | {
81 | MessageBox.Show("Wrong Encryption Key Format.\r\nMust be HEX!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
82 | tbKey.Focus();
83 | return;
84 | }
85 |
86 | Array.Clear(EncryptionRow.Key, 0, 5);
87 | if (key.Length > 0)
88 | Buffer.BlockCopy(key, 0, EncryptionRow.Key, 0, key.Length > P25DESEncryptionRow.KEY_SIZE ? P25DESEncryptionRow.KEY_SIZE : key.Length);
89 |
90 | EncryptionRow.Frequency = freq;
91 | EncryptionRow.ActivateOptions = optionsControl.Options;
92 |
93 | EncryptionRow.Notes = tbNotes.Text.Trim();
94 |
95 | DialogResult = DialogResult.OK;
96 | Close();
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/P25DESEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("P25 DES")]
7 | [Serializable]
8 | public class P25DESEncryptionRow : P25EncryptionRow
9 | {
10 | public const int KEY_SIZE = 8;
11 |
12 | public byte[] Key { get; set; }
13 |
14 | [JsonIgnore]
15 | public override string Description
16 | {
17 | get
18 | {
19 | if (!string.IsNullOrEmpty($"{ActivateOptions}"))
20 | return $"P25 DES: {ActivateOptions}";
21 | else
22 | return $"P25 DES";
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/P25EncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [Serializable]
7 | public abstract class P25EncryptionRow : BaseEncryptionRow
8 | {
9 | public P25ActivateOptions ActivateOptions { get; set; }
10 |
11 | [JsonIgnore]
12 | public override ProtocolEnum Protocol => ProtocolEnum.P25;
13 |
14 | public override bool IsFrequencyNeed => ActivateOptions == null ? true : ActivateOptions.IsActivated(P25SelectedActivateOptionsEnum.Frequency);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/P25SelectedActivateOptionsEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | [System.Flags]
4 | public enum P25SelectedActivateOptionsEnum : uint
5 | {
6 | NAC = 1 << 0,
7 | GroupID = 1 << 1,
8 | Frequency = 1 << 2,
9 | KeyID = 1 << 3,
10 | SourceID = 1 << 4,
11 |
12 | ForceMute = 1 << 15
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | internal static class Program
7 | {
8 | ///
9 | /// The main entry point for the application.
10 | ///
11 | [STAThread]
12 | static void Main(string[] args)
13 | {
14 | Application.EnableVisualStyles();
15 | Application.SetCompatibleTextRenderingDefault(false);
16 | Application.Run(new MainForm(args.Length > 0 ? args[0] : null));
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Project.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace CFT
8 | {
9 | [Serializable]
10 | public class Project
11 | {
12 | [JsonIgnore]
13 | public string Path { get; set; }
14 | public List Scanners { get; set; }
15 | public List EcryptionRows { get; set; }
16 |
17 | public static Project Load(string fileName)
18 | {
19 | var p = JsonConvert.DeserializeObject(SuperComplexDeobfuscator(File.ReadAllBytes(fileName)), new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
20 | p.Path = fileName;
21 | return p;
22 | }
23 |
24 | public void Save()
25 | {
26 | File.WriteAllBytes(Path, SuperComplexObfuscator(JsonConvert.SerializeObject(this, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto } )));
27 | }
28 |
29 | private static byte[] SuperComplexObfuscator(string str)
30 | {
31 | var bs = Encoding.UTF8.GetBytes(str);
32 | for(var i=0; i
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace CFT.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/ProtocolEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum ProtocolEnum
4 | {
5 | All = 0,
6 | DMR = 1,
7 | NXDN = 2,
8 | P25 = 3
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Scanner.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CFT
4 | {
5 | [Serializable]
6 | public class Scanner
7 | {
8 | public string Name { get; set; }
9 |
10 | public ScannerModelEnum Model { get; set; }
11 |
12 | public Licensing Licensing { get; set; }
13 |
14 | public KeyMapping KeyMapping { get; set; }
15 |
16 | public bool MuteEncryptedVoiceTraffic { get; set; }
17 |
18 | public byte[] MacAddress { get; set; }
19 |
20 | public DisplayAdditionalInfo DisplayAdditionalInfo { get; set; }
21 |
22 | public bool LEDAlertWhileDigitalVoiceGoesOn { get; set; }
23 |
24 | public Scanner()
25 | {
26 | Model = ScannerModelEnum.BCD436HP;
27 | Name = "Scanner";
28 | MacAddress = new byte[6];
29 | }
30 |
31 | public override string ToString()
32 | {
33 | if (string.IsNullOrEmpty(Name))
34 | return $"{Model}";
35 | return $"{Name.Trim()} ({Model})";
36 | }
37 |
38 | public static ScannerBaseModelEnum GetBaseModel(ScannerModelEnum model)
39 | {
40 | switch(model)
41 | {
42 | case ScannerModelEnum.BCD436HP:
43 | case ScannerModelEnum.BCD536HP:
44 | case ScannerModelEnum.UBCD3600XLT:
45 | case ScannerModelEnum.UBCD436PT:
46 | case ScannerModelEnum.UBCD536PT:
47 | return ScannerBaseModelEnum.BCD;
48 |
49 | default:
50 | return ScannerBaseModelEnum.SDS;
51 | }
52 | }
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/ScannerAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CFT
4 | {
5 | [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
6 | public class ScannerAttribute : Attribute
7 | {
8 | public ScannerModelEnum Model { get; private set; }
9 | public ScannerAttribute(ScannerModelEnum model)
10 | {
11 | Model = model;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/ScannerBaseModelEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum ScannerBaseModelEnum
4 | {
5 | BCD = 0,
6 | SDS = 1
7 | }
8 | }
--------------------------------------------------------------------------------
/src/ScannerForm.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Forms;
2 |
3 | namespace CFT
4 | {
5 | public partial class ScannerForm : Form
6 | {
7 | public Scanner Scanner { get; private set; }
8 | private KeyMapping _keyMapping = new KeyMapping();
9 |
10 | public ScannerForm(Scanner scanner)
11 | {
12 | InitializeComponent();
13 |
14 | Scanner = scanner == null ? new Scanner() : Utils.DeepClone(scanner);
15 | _keyMapping = Scanner.KeyMapping;
16 |
17 | Utils.FillComboBoxData(cbModel, typeof(ScannerModelEnum));
18 | if (!Utils.SetComboBoxData(cbModel, Scanner.Model))
19 | cbModel.SelectedIndex = 0;
20 |
21 | cbMute.Checked = Scanner.MuteEncryptedVoiceTraffic;
22 | cbLedAlertWhile.Checked = Scanner.LEDAlertWhileDigitalVoiceGoesOn;
23 | tbName.Text = Scanner.Name;
24 | UpdateControls();
25 | }
26 |
27 | private void btnOk_Click(object sender, System.EventArgs e)
28 | {
29 | Scanner.Model = (ScannerModelEnum)Utils.GetComboBoxData(cbModel.SelectedItem);
30 | Scanner.Name = tbName.Text.Trim();
31 | Scanner.KeyMapping = _keyMapping;
32 | Scanner.MuteEncryptedVoiceTraffic = cbMute.Checked;
33 | Scanner.LEDAlertWhileDigitalVoiceGoesOn = cbLedAlertWhile.Checked;
34 | }
35 |
36 | private void btnLicenses_Click(object sender, System.EventArgs e)
37 | {
38 | var frm = new LicensingForm(Scanner.Licensing);
39 | if (frm.ShowDialog() == DialogResult.OK)
40 | {
41 | Scanner.Licensing = frm.Licensing;
42 | UpdateControls();
43 | }
44 | }
45 |
46 | private void btnKeyMappings_Click(object sender, System.EventArgs e)
47 | {
48 | var model = (ScannerModelEnum)Utils.GetComboBoxData(cbModel.SelectedItem);
49 | var frm = new KeyMappingForm(model, _keyMapping);
50 | if (frm.ShowDialog() == DialogResult.OK)
51 | {
52 | _keyMapping = frm.KeyMapping;
53 | }
54 | }
55 |
56 | private void cbModel_SelectedIndexChanged(object sender, System.EventArgs e)
57 | {
58 | try
59 | {
60 | var model = (ScannerModelEnum)Utils.GetComboBoxData(cbModel.SelectedItem);
61 | // todo selecting from ScannerModelEnum
62 | btnMacAddress.Enabled = model == ScannerModelEnum.SDS200 || model == ScannerModelEnum.SDS200E;
63 | }
64 | catch
65 | {
66 | btnMacAddress.Enabled = false;
67 | }
68 | }
69 |
70 | private void btnMacAddress_Click(object sender, System.EventArgs e)
71 | {
72 | var frm = new MacAddressForm(Scanner.MacAddress);
73 | if (frm.ShowDialog() == DialogResult.OK)
74 | {
75 | Scanner.MacAddress = frm.MacAddress;
76 | }
77 | }
78 |
79 | private void btnDisplayAdditionalInfo_Click(object sender, System.EventArgs e)
80 | {
81 | var model = (ScannerModelEnum)Utils.GetComboBoxData(cbModel.SelectedItem);
82 |
83 | var frm = new DisplayAdditionalInfoForm(model, Scanner.DisplayAdditionalInfo);
84 | if (frm.ShowDialog() == DialogResult.OK)
85 | {
86 | Scanner.DisplayAdditionalInfo = frm.DisplayAdditionalInfo;
87 | }
88 | }
89 |
90 | private void UpdateControls()
91 | {
92 | cbLedAlertWhile.Enabled = Scanner.Licensing == null ? false : Scanner.Licensing.IsKeysExist;
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/ScannerForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/ScannerListForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows.Forms;
4 |
5 | namespace CFT
6 | {
7 | public partial class ScannerListForm : Form
8 | {
9 | public List Scanners { get; private set; }
10 |
11 | public ScannerListForm(List scanners)
12 | {
13 | InitializeComponent();
14 |
15 | Scanners = scanners == null ? new List() : scanners;
16 |
17 | FillScannerListBox();
18 | UpdateControls();
19 | }
20 |
21 | private void FillScannerListBox()
22 | {
23 | lbScanners.Items.Clear();
24 | foreach (var item in Scanners)
25 | {
26 | lbScanners.Items.Add(new DisplayTagObject(item));
27 | }
28 | if (lbScanners.Items.Count > 0)
29 | lbScanners.SelectedIndex = 0;
30 | }
31 |
32 | private void UpdateControls()
33 | {
34 | btnEdit.Enabled = lbScanners.SelectedIndex >= 0;
35 | btnDelete.Enabled = lbScanners.SelectedIndex >= 0;
36 | btnLicenses.Enabled = lbScanners.SelectedIndex >= 0;
37 | lbScanners.Invalidate();
38 | }
39 |
40 | private void lbScanners_SelectedIndexChanged(object sender, EventArgs e)
41 | {
42 | UpdateControls();
43 | }
44 |
45 | private void btnDelete_Click(object sender, EventArgs e)
46 | {
47 | if (MessageBox.Show("Delete?", "Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
48 | {
49 | Scanners.RemoveAt(lbScanners.SelectedIndex);
50 | FillScannerListBox();
51 | UpdateControls();
52 | }
53 | }
54 |
55 | private void btnAdd_Click(object sender, EventArgs e)
56 | {
57 | var frm = new ScannerForm(null);
58 | if (frm.ShowDialog() == DialogResult.OK)
59 | {
60 | Scanners.Add(frm.Scanner);
61 | FillScannerListBox();
62 | UpdateControls();
63 | }
64 | }
65 |
66 | private void btnEdit_Click(object sender, EventArgs e)
67 | {
68 | if (lbScanners.SelectedIndex == -1)
69 | return;
70 |
71 | var frm = new ScannerForm(Scanners[lbScanners.SelectedIndex]);
72 | if (frm.ShowDialog() == DialogResult.OK)
73 | {
74 | Scanners[lbScanners.SelectedIndex] = frm.Scanner;
75 | FillScannerListBox();
76 | UpdateControls();
77 | }
78 | }
79 |
80 | private void lbScanners_DoubleClick(object sender, EventArgs e)
81 | {
82 | btnEdit_Click(sender, e);
83 | }
84 |
85 | private void lbScanners_KeyPress(object sender, KeyPressEventArgs e)
86 | {
87 | if (e.KeyChar == 13)
88 | btnEdit_Click(sender, e);
89 | }
90 |
91 | private void btnLicenses_Click(object sender, EventArgs e)
92 | {
93 | if (lbScanners.SelectedIndex == -1)
94 | return;
95 |
96 | var frm = new LicensingForm(Scanners[lbScanners.SelectedIndex].Licensing);
97 | if (frm.ShowDialog() == DialogResult.OK)
98 | {
99 | Scanners[lbScanners.SelectedIndex].Licensing = frm.Licensing;
100 | }
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/ScannerListForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/ScannerModelEnum.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | public enum ScannerModelEnum : byte
4 | {
5 | BCD436HP = 1,
6 | BCD536HP = 2,
7 | SDS100 = 3,
8 | SDS200 = 4,
9 | UBCD3600XLT = 5,
10 | SDS100E = 6,
11 | SDS200E = 7,
12 | UBCD436PT = 8,
13 | UBCD536PT = 9,
14 | USDS100 = 10
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/SelectEncryptionMethodForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace CFT
2 | {
3 | partial class SelectEncryptionMethodForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.listBox = new System.Windows.Forms.ListBox();
32 | this.btnSelect = new System.Windows.Forms.Button();
33 | this.btnCancel = new System.Windows.Forms.Button();
34 | this.SuspendLayout();
35 | //
36 | // listBox
37 | //
38 | this.listBox.FormattingEnabled = true;
39 | this.listBox.ItemHeight = 17;
40 | this.listBox.Location = new System.Drawing.Point(12, 12);
41 | this.listBox.Name = "listBox";
42 | this.listBox.Size = new System.Drawing.Size(217, 225);
43 | this.listBox.TabIndex = 0;
44 | //
45 | // btnSelect
46 | //
47 | this.btnSelect.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
48 | this.btnSelect.DialogResult = System.Windows.Forms.DialogResult.OK;
49 | this.btnSelect.Location = new System.Drawing.Point(127, 251);
50 | this.btnSelect.Name = "btnSelect";
51 | this.btnSelect.Size = new System.Drawing.Size(102, 32);
52 | this.btnSelect.TabIndex = 1;
53 | this.btnSelect.Text = "OK";
54 | this.btnSelect.UseVisualStyleBackColor = true;
55 | this.btnSelect.Click += new System.EventHandler(this.btnSelect_Click);
56 | //
57 | // btnCancel
58 | //
59 | this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
60 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
61 | this.btnCancel.Location = new System.Drawing.Point(12, 251);
62 | this.btnCancel.Name = "btnCancel";
63 | this.btnCancel.Size = new System.Drawing.Size(102, 32);
64 | this.btnCancel.TabIndex = 2;
65 | this.btnCancel.Text = "Cancel";
66 | this.btnCancel.UseVisualStyleBackColor = true;
67 | //
68 | // SelectEncryptionMethodForm
69 | //
70 | this.AcceptButton = this.btnSelect;
71 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
72 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
73 | this.CancelButton = this.btnCancel;
74 | this.ClientSize = new System.Drawing.Size(241, 295);
75 | this.Controls.Add(this.btnSelect);
76 | this.Controls.Add(this.btnCancel);
77 | this.Controls.Add(this.listBox);
78 | this.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
79 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
80 | this.Margin = new System.Windows.Forms.Padding(4);
81 | this.MaximizeBox = false;
82 | this.MinimizeBox = false;
83 | this.Name = "SelectEncryptionMethodForm";
84 | this.ShowIcon = false;
85 | this.ShowInTaskbar = false;
86 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
87 | this.Text = "Select Encryption Method";
88 | this.ResumeLayout(false);
89 |
90 | }
91 |
92 | #endregion
93 |
94 | private System.Windows.Forms.ListBox listBox;
95 | private System.Windows.Forms.Button btnSelect;
96 | private System.Windows.Forms.Button btnCancel;
97 | }
98 | }
--------------------------------------------------------------------------------
/src/SelectEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class SelectEncryptionMethodForm : Form
7 | {
8 | public int Selection { get; private set; }
9 |
10 | public SelectEncryptionMethodForm()
11 | {
12 | InitializeComponent();
13 |
14 | foreach(var item in Enum.GetValues(typeof(EncryptionMethodEnum)))
15 | {
16 | listBox.Items.Add(DisplayNameAttribute.GetName(item));
17 | }
18 | listBox.SelectedIndex = 0;
19 | }
20 |
21 | private void btnSelect_Click(object sender, System.EventArgs e)
22 | {
23 | Selection = listBox.SelectedIndex;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/TyteraBPEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class TyteraBPEncryptionMethodForm : Form
7 | {
8 | public TyteraBPEncryptionRow EncryptionRow { get; private set; }
9 |
10 | public bool IsBatchMode { get; private set; }
11 |
12 | public TyteraBPEncryptionMethodForm(TyteraBPEncryptionRow row = null, bool batchMode = false)
13 | {
14 | InitializeComponent();
15 |
16 | optionsControl.OptionChanged += OptionsControl_OptionChanged;
17 |
18 | IsBatchMode = batchMode;
19 | if (IsBatchMode)
20 | {
21 | Text += " (Batch mode)";
22 | tbFrequency.Enabled = false;
23 | tbNotes.Enabled = false;
24 | }
25 |
26 | if (row == null)
27 | {
28 | EncryptionRow = new TyteraBPEncryptionRow();
29 | if (!IsBatchMode)
30 | tbFrequency.Text = Utils.GetFrequencyString(145500000);
31 | optionsControl.SetOptions(null);
32 | }
33 | else
34 | {
35 | EncryptionRow = row;
36 | if (!IsBatchMode)
37 | tbFrequency.Text = Utils.GetFrequencyString(row.Frequency);
38 | optionsControl.SetOptions(row.ActivateOptions);
39 | nudKey.Value = row.Key;
40 | tbNotes.Text = row.Notes;
41 | }
42 | OptionsControl_OptionChanged(this, null);
43 | }
44 |
45 | private void OptionsControl_OptionChanged(object sender, EventArgs e)
46 | {
47 | tbFrequency.Enabled = optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.Frequency);
48 | nudKey.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
49 | }
50 |
51 |
52 | private void btnOK_Click(object sender, EventArgs e)
53 | {
54 | string errorStr;
55 |
56 | if (optionsControl.IsExistErrors(out errorStr))
57 | {
58 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
59 | return;
60 | }
61 |
62 | uint freq = 0;
63 | if (!IsBatchMode && !Utils.ParseFrequency(tbFrequency.Text, out freq, out errorStr))
64 | {
65 | tbFrequency.Focus();
66 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
67 | return;
68 | }
69 |
70 | EncryptionRow.Frequency = freq;
71 | EncryptionRow.ActivateOptions = optionsControl.Options;
72 | EncryptionRow.Key = (ushort)nudKey.Value;
73 | EncryptionRow.Notes = tbNotes.Text.Trim();
74 |
75 | DialogResult = DialogResult.OK;
76 | Close();
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/TyteraBPEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("TYT BP")]
7 | [Serializable]
8 | public class TyteraBPEncryptionRow : DmrEncryptionRow
9 | {
10 | public ushort Key { get; set; }
11 |
12 | [JsonIgnore]
13 | public override string Description
14 | {
15 | get
16 | {
17 | if (!string.IsNullOrEmpty($"{ActivateOptions}"))
18 | return $"Tytera BP: {ActivateOptions}";
19 | else
20 | return $"Tytera BP";
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/TyteraEPEncryptionMethodForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace CFT
5 | {
6 | public partial class TyteraEPEncryptionMethodForm : Form
7 | {
8 | public TyteraEPEncryptionRow EncryptionRow { get; private set; }
9 | public bool IsBatchMode { get; private set; }
10 |
11 | public TyteraEPEncryptionMethodForm(TyteraEPEncryptionRow row = null, bool batchMode = false)
12 | {
13 | InitializeComponent();
14 |
15 | optionsControl.OptionChanged += OptionsControl_OptionChanged;
16 |
17 | IsBatchMode = batchMode;
18 | if (IsBatchMode)
19 | {
20 | Text += " (Batch mode)";
21 | tbFrequency.Enabled = false;
22 | tbNotes.Enabled = false;
23 | }
24 |
25 | if (row == null)
26 | {
27 | EncryptionRow = new TyteraEPEncryptionRow();
28 | EncryptionRow.Key = new byte[TyteraEPEncryptionRow.KEY_SIZE];
29 | if (!IsBatchMode)
30 | tbFrequency.Text = Utils.GetFrequencyString(145500000);
31 | optionsControl.SetOptions(null);
32 | }
33 | else
34 | {
35 | EncryptionRow = row;
36 | if (!IsBatchMode)
37 | tbFrequency.Text = Utils.GetFrequencyString(row.Frequency);
38 | optionsControl.SetOptions(row.ActivateOptions);
39 |
40 | if (Utils.IsArrayEmpty(row.Key))
41 | tbKey.Text = string.Empty;
42 | else
43 | tbKey.Text = Utils.BytesToHexString(row.Key);
44 |
45 | tbNotes.Text = row.Notes;
46 | }
47 | OptionsControl_OptionChanged(this, null);
48 | }
49 |
50 | private void OptionsControl_OptionChanged(object sender, EventArgs e)
51 | {
52 | tbFrequency.Enabled = optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.Frequency);
53 | tbKey.Enabled = !optionsControl.Options.IsActivated(DmrSelectedActivateOptionsEnum.ForceMute);
54 | }
55 |
56 | private void btnOK_Click(object sender, EventArgs e)
57 | {
58 | string errorStr;
59 |
60 | if (optionsControl.IsExistErrors(out errorStr))
61 | {
62 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
63 | return;
64 | }
65 |
66 | uint freq = 0;
67 | if (!IsBatchMode && !Utils.ParseFrequency(tbFrequency.Text, out freq, out errorStr))
68 | {
69 | tbFrequency.Focus();
70 | MessageBox.Show(errorStr, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
71 | return;
72 | }
73 |
74 | byte[] key;
75 | try
76 | {
77 | key = Utils.HexStringToBytes(tbKey.Text);
78 | }
79 | catch
80 | {
81 | MessageBox.Show("Wrong Encryption Key Format.\r\nMust be HEX!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
82 | tbKey.Focus();
83 | return;
84 | }
85 |
86 | Array.Clear(EncryptionRow.Key, 0, 5);
87 | if (key.Length > 0)
88 | Buffer.BlockCopy(key, 0, EncryptionRow.Key, 0, key.Length > TyteraEPEncryptionRow.KEY_SIZE ? TyteraEPEncryptionRow.KEY_SIZE : key.Length);
89 |
90 | EncryptionRow.Frequency = freq;
91 | EncryptionRow.ActivateOptions = optionsControl.Options;
92 |
93 | EncryptionRow.Notes = tbNotes.Text.Trim();
94 |
95 | DialogResult = DialogResult.OK;
96 | Close();
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/TyteraEPEncryptionRow.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CFT
5 | {
6 | [DisplayName("TYT EP")]
7 | [Serializable]
8 | public class TyteraEPEncryptionRow : DmrEncryptionRow
9 | {
10 | public const int KEY_SIZE = 16;
11 |
12 | public byte[] Key { get; set; }
13 |
14 | [JsonIgnore]
15 | public override string Description
16 | {
17 | get
18 | {
19 | if (!string.IsNullOrEmpty($"{ActivateOptions}"))
20 | return $"Tytera EP: {ActivateOptions}";
21 | else
22 | return $"Tytera EP";
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/app.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/src/app.ico
--------------------------------------------------------------------------------
/src/fakesign.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/src/fakesign.snk
--------------------------------------------------------------------------------
/src/images/JD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/src/images/JD.png
--------------------------------------------------------------------------------
/src/images/add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/src/images/add.png
--------------------------------------------------------------------------------
/src/images/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/src/images/delete.png
--------------------------------------------------------------------------------
/src/images/down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/src/images/down.png
--------------------------------------------------------------------------------
/src/images/duplicate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/src/images/duplicate.png
--------------------------------------------------------------------------------
/src/images/new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/src/images/new.png
--------------------------------------------------------------------------------
/src/images/open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/src/images/open.png
--------------------------------------------------------------------------------
/src/images/save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/src/images/save.png
--------------------------------------------------------------------------------
/src/images/up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x27/CFT/2d2456d45351dae49daf81b74c9a3fa59e14e3c4/src/images/up.png
--------------------------------------------------------------------------------
/src/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------